WeightedRoundRobin load balancer
Co-authored-by: Ludovic Fernandez <ldez@users.noreply.github.com>
This commit is contained in:
parent
84de444325
commit
6fed76a687
44 changed files with 1612 additions and 833 deletions
|
@ -198,11 +198,13 @@ spec:
|
||||||
# "Parameter", etc, to support simpler forms of rule matching, but for now we
|
# "Parameter", etc, to support simpler forms of rule matching, but for now we
|
||||||
# only support "Rule".
|
# only support "Rule".
|
||||||
kind: Rule
|
kind: Rule
|
||||||
# Priority disambiguates rules of the same length, for route matching.
|
# (optional) Priority disambiguates rules of the same length, for route matching.
|
||||||
priority: 12
|
priority: 12
|
||||||
services:
|
services:
|
||||||
- name: whoami
|
- name: whoami
|
||||||
port: 80
|
port: 80
|
||||||
|
# (default 1) A weight used by the weighted round-robin strategy (WRR).
|
||||||
|
weight: 1
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -130,10 +130,10 @@
|
||||||
- "traefik.http.services.service0.loadbalancer.healthcheck.timeout=foobar"
|
- "traefik.http.services.service0.loadbalancer.healthcheck.timeout=foobar"
|
||||||
- "traefik.http.services.service0.loadbalancer.passhostheader=true"
|
- "traefik.http.services.service0.loadbalancer.passhostheader=true"
|
||||||
- "traefik.http.services.service0.loadbalancer.responseforwarding.flushinterval=foobar"
|
- "traefik.http.services.service0.loadbalancer.responseforwarding.flushinterval=foobar"
|
||||||
- "traefik.http.services.service0.loadbalancer.stickiness=true"
|
- "traefik.http.services.service0.loadbalancer.sticky=true"
|
||||||
- "traefik.http.services.service0.loadbalancer.stickiness.cookiename=foobar"
|
- "traefik.http.services.service0.loadbalancer.sticky.cookie.name=foobar"
|
||||||
- "traefik.http.services.service0.loadbalancer.stickiness.httponlycookie=true"
|
- "traefik.http.services.service0.loadbalancer.sticky.cookie.httponly=true"
|
||||||
- "traefik.http.services.service0.loadbalancer.stickiness.securecookie=true"
|
- "traefik.http.services.service0.loadbalancer.sticky.cookie.secure=true"
|
||||||
- "traefik.http.services.service0.loadbalancer.server.port=foobar"
|
- "traefik.http.services.service0.loadbalancer.server.port=foobar"
|
||||||
- "traefik.http.services.service0.loadbalancer.server.scheme=foobar"
|
- "traefik.http.services.service0.loadbalancer.server.scheme=foobar"
|
||||||
- "traefik.http.services.service1.loadbalancer.healthcheck.headers.name0=foobar"
|
- "traefik.http.services.service1.loadbalancer.healthcheck.headers.name0=foobar"
|
||||||
|
@ -146,10 +146,10 @@
|
||||||
- "traefik.http.services.service1.loadbalancer.healthcheck.timeout=foobar"
|
- "traefik.http.services.service1.loadbalancer.healthcheck.timeout=foobar"
|
||||||
- "traefik.http.services.service1.loadbalancer.passhostheader=true"
|
- "traefik.http.services.service1.loadbalancer.passhostheader=true"
|
||||||
- "traefik.http.services.service1.loadbalancer.responseforwarding.flushinterval=foobar"
|
- "traefik.http.services.service1.loadbalancer.responseforwarding.flushinterval=foobar"
|
||||||
- "traefik.http.services.service1.loadbalancer.stickiness=true"
|
- "traefik.http.services.service1.loadbalancer.sticky=true"
|
||||||
- "traefik.http.services.service1.loadbalancer.stickiness.cookiename=foobar"
|
- "traefik.http.services.service1.loadbalancer.sticky.cookie.name=foobar"
|
||||||
- "traefik.http.services.service1.loadbalancer.stickiness.httponlycookie=true"
|
- "traefik.http.services.service1.loadbalancer.sticky.cookie.httponly=true"
|
||||||
- "traefik.http.services.service1.loadbalancer.stickiness.securecookie=true"
|
- "traefik.http.services.service1.loadbalancer.sticky.cookie.secure=true"
|
||||||
- "traefik.http.services.service1.loadbalancer.server.port=foobar"
|
- "traefik.http.services.service1.loadbalancer.server.port=foobar"
|
||||||
- "traefik.http.services.service1.loadbalancer.server.scheme=foobar"
|
- "traefik.http.services.service1.loadbalancer.server.scheme=foobar"
|
||||||
- "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar"
|
- "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar"
|
||||||
|
|
|
@ -35,56 +35,47 @@
|
||||||
main = "foobar"
|
main = "foobar"
|
||||||
sans = ["foobar", "foobar"]
|
sans = ["foobar", "foobar"]
|
||||||
[http.services]
|
[http.services]
|
||||||
[http.services.Service0]
|
[http.services.Service01]
|
||||||
[http.services.Service0.loadBalancer]
|
[http.services.Service01.loadBalancer]
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
[http.services.Service0.loadBalancer.stickiness]
|
[http.services.Service01.loadBalancer.sticky]
|
||||||
cookieName = "foobar"
|
[http.services.Service01.loadBalancer.sticky.cookie]
|
||||||
secureCookie = true
|
name = "foobar"
|
||||||
httpOnlyCookie = true
|
secure = true
|
||||||
|
httpOnly = true
|
||||||
|
|
||||||
[[http.services.Service0.loadBalancer.servers]]
|
[[http.services.Service01.loadBalancer.servers]]
|
||||||
url = "foobar"
|
url = "foobar"
|
||||||
|
|
||||||
[[http.services.Service0.loadBalancer.servers]]
|
[[http.services.Service01.loadBalancer.servers]]
|
||||||
url = "foobar"
|
url = "foobar"
|
||||||
[http.services.Service0.loadBalancer.healthCheck]
|
[http.services.Service01.loadBalancer.healthCheck]
|
||||||
scheme = "foobar"
|
scheme = "foobar"
|
||||||
path = "foobar"
|
path = "foobar"
|
||||||
port = 42
|
port = 42
|
||||||
interval = "foobar"
|
interval = "foobar"
|
||||||
timeout = "foobar"
|
timeout = "foobar"
|
||||||
hostname = "foobar"
|
hostname = "foobar"
|
||||||
[http.services.Service0.loadBalancer.healthCheck.headers]
|
[http.services.Service01.loadBalancer.healthCheck.headers]
|
||||||
name0 = "foobar"
|
name0 = "foobar"
|
||||||
name1 = "foobar"
|
name1 = "foobar"
|
||||||
[http.services.Service0.loadBalancer.responseForwarding]
|
[http.services.Service01.loadBalancer.responseForwarding]
|
||||||
flushInterval = "foobar"
|
flushInterval = "foobar"
|
||||||
[http.services.Service1]
|
[http.services.Service02]
|
||||||
[http.services.Service1.loadBalancer]
|
[http.services.Service02.weighted]
|
||||||
passHostHeader = true
|
|
||||||
[http.services.Service1.loadBalancer.stickiness]
|
|
||||||
cookieName = "foobar"
|
|
||||||
secureCookie = true
|
|
||||||
httpOnlyCookie = true
|
|
||||||
|
|
||||||
[[http.services.Service1.loadBalancer.servers]]
|
[[http.services.Service02.weighted.services]]
|
||||||
url = "foobar"
|
name = "foobar"
|
||||||
|
weight = 42
|
||||||
|
|
||||||
[[http.services.Service1.loadBalancer.servers]]
|
[[http.services.Service02.weighted.services]]
|
||||||
url = "foobar"
|
name = "foobar"
|
||||||
[http.services.Service1.loadBalancer.healthCheck]
|
weight = 42
|
||||||
scheme = "foobar"
|
[http.services.Service02.weighted.sticky]
|
||||||
path = "foobar"
|
[http.services.Service02.weighted.sticky.cookie]
|
||||||
port = 42
|
name = "foobar"
|
||||||
interval = "foobar"
|
secure = true
|
||||||
timeout = "foobar"
|
httpOnly = true
|
||||||
hostname = "foobar"
|
|
||||||
[http.services.Service1.loadBalancer.healthCheck.headers]
|
|
||||||
name0 = "foobar"
|
|
||||||
name1 = "foobar"
|
|
||||||
[http.services.Service1.loadBalancer.responseForwarding]
|
|
||||||
flushInterval = "foobar"
|
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.Middleware00]
|
[http.middlewares.Middleware00]
|
||||||
[http.middlewares.Middleware00.addPrefix]
|
[http.middlewares.Middleware00.addPrefix]
|
||||||
|
|
|
@ -45,34 +45,13 @@ http:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
services:
|
services:
|
||||||
Service0:
|
Service01:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
stickiness:
|
sticky:
|
||||||
cookieName: foobar
|
cookie:
|
||||||
secureCookie: true
|
name: foobar
|
||||||
httpOnlyCookie: true
|
secure: true
|
||||||
servers:
|
httpOnly: true
|
||||||
- url: foobar
|
|
||||||
- url: foobar
|
|
||||||
healthCheck:
|
|
||||||
scheme: foobar
|
|
||||||
path: foobar
|
|
||||||
port: 42
|
|
||||||
interval: foobar
|
|
||||||
timeout: foobar
|
|
||||||
hostname: foobar
|
|
||||||
headers:
|
|
||||||
name0: foobar
|
|
||||||
name1: foobar
|
|
||||||
passHostHeader: true
|
|
||||||
responseForwarding:
|
|
||||||
flushInterval: foobar
|
|
||||||
Service1:
|
|
||||||
loadBalancer:
|
|
||||||
stickiness:
|
|
||||||
cookieName: foobar
|
|
||||||
secureCookie: true
|
|
||||||
httpOnlyCookie: true
|
|
||||||
servers:
|
servers:
|
||||||
- url: foobar
|
- url: foobar
|
||||||
- url: foobar
|
- url: foobar
|
||||||
|
@ -89,6 +68,18 @@ http:
|
||||||
passHostHeader: true
|
passHostHeader: true
|
||||||
responseForwarding:
|
responseForwarding:
|
||||||
flushInterval: foobar
|
flushInterval: foobar
|
||||||
|
Service02:
|
||||||
|
weighted:
|
||||||
|
services:
|
||||||
|
- name: foobar
|
||||||
|
weight: 42
|
||||||
|
- name: foobar
|
||||||
|
weight: 42
|
||||||
|
sticky:
|
||||||
|
cookie:
|
||||||
|
name: foobar
|
||||||
|
secure: true
|
||||||
|
httpOnly: true
|
||||||
middlewares:
|
middlewares:
|
||||||
Middleware00:
|
Middleware00:
|
||||||
addPrefix:
|
addPrefix:
|
||||||
|
|
|
@ -130,10 +130,10 @@
|
||||||
"traefik.http.services.service0.loadbalancer.healthcheck.timeout": "foobar",
|
"traefik.http.services.service0.loadbalancer.healthcheck.timeout": "foobar",
|
||||||
"traefik.http.services.service0.loadbalancer.passhostheader": "true",
|
"traefik.http.services.service0.loadbalancer.passhostheader": "true",
|
||||||
"traefik.http.services.service0.loadbalancer.responseforwarding.flushinterval": "foobar",
|
"traefik.http.services.service0.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||||
"traefik.http.services.service0.loadbalancer.stickiness": "true",
|
"traefik.http.services.service0.loadbalancer.sticky": "true",
|
||||||
"traefik.http.services.service0.loadbalancer.stickiness.cookiename": "foobar",
|
"traefik.http.services.service0.loadbalancer.sticky.cookie.name": "foobar",
|
||||||
"traefik.http.services.service0.loadbalancer.stickiness.httponlycookie": "true",
|
"traefik.http.services.service0.loadbalancer.sticky.cookie.httponly": "true",
|
||||||
"traefik.http.services.service0.loadbalancer.stickiness.securecookie": "true",
|
"traefik.http.services.service0.loadbalancer.sticky.cookie.secure": "true",
|
||||||
"traefik.http.services.service0.loadbalancer.server.port": "foobar",
|
"traefik.http.services.service0.loadbalancer.server.port": "foobar",
|
||||||
"traefik.http.services.service0.loadbalancer.server.scheme": "foobar",
|
"traefik.http.services.service0.loadbalancer.server.scheme": "foobar",
|
||||||
"traefik.http.services.service1.loadbalancer.healthcheck.headers.name0": "foobar",
|
"traefik.http.services.service1.loadbalancer.healthcheck.headers.name0": "foobar",
|
||||||
|
@ -146,10 +146,10 @@
|
||||||
"traefik.http.services.service1.loadbalancer.healthcheck.timeout": "foobar",
|
"traefik.http.services.service1.loadbalancer.healthcheck.timeout": "foobar",
|
||||||
"traefik.http.services.service1.loadbalancer.passhostheader": "true",
|
"traefik.http.services.service1.loadbalancer.passhostheader": "true",
|
||||||
"traefik.http.services.service1.loadbalancer.responseforwarding.flushinterval": "foobar",
|
"traefik.http.services.service1.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||||
"traefik.http.services.service1.loadbalancer.stickiness": "true",
|
"traefik.http.services.service1.loadbalancer.sticky": "true",
|
||||||
"traefik.http.services.service1.loadbalancer.stickiness.cookiename": "foobar",
|
"traefik.http.services.service1.loadbalancer.sticky.cookie.name": "foobar",
|
||||||
"traefik.http.services.service1.loadbalancer.stickiness.httponlycookie": "true",
|
"traefik.http.services.service1.loadbalancer.sticky.cookie.secure": "true",
|
||||||
"traefik.http.services.service1.loadbalancer.stickiness.securecookie": "true",
|
"traefik.http.services.service1.loadbalancer.sticky.cookie.httponly": "true",
|
||||||
"traefik.http.services.service1.loadbalancer.server.port": "foobar",
|
"traefik.http.services.service1.loadbalancer.server.port": "foobar",
|
||||||
"traefik.http.services.service1.loadbalancer.server.scheme": "foobar",
|
"traefik.http.services.service1.loadbalancer.server.scheme": "foobar",
|
||||||
"traefik.tcp.routers.tcprouter0.entrypoints": "foobar, foobar",
|
"traefik.tcp.routers.tcprouter0.entrypoints": "foobar, foobar",
|
||||||
|
|
|
@ -54,13 +54,7 @@ The `Services` are responsible for configuring how to reach the actual services
|
||||||
|
|
||||||
## Configuring HTTP Services
|
## Configuring HTTP Services
|
||||||
|
|
||||||
### General
|
### Servers Load Balancer
|
||||||
|
|
||||||
Currently, `LoadBalancer` is the only supported kind of HTTP `Service` (see below).
|
|
||||||
However, since Traefik is an ever evolving project, other kind of HTTP Services will be available in the future,
|
|
||||||
reason why you have to specify it.
|
|
||||||
|
|
||||||
### Load Balancer
|
|
||||||
|
|
||||||
The load balancers are able to load balance the requests between multiple instances of your programs.
|
The load balancers are able to load balance the requests between multiple instances of your programs.
|
||||||
|
|
||||||
|
@ -161,7 +155,7 @@ On subsequent requests, the client is forwarded to the same server.
|
||||||
```toml tab="TOML"
|
```toml tab="TOML"
|
||||||
[http.services]
|
[http.services]
|
||||||
[http.services.my-service]
|
[http.services.my-service]
|
||||||
[http.services.my-service.loadBalancer.stickiness]
|
[http.services.my-service.loadBalancer.sticky.cookie]
|
||||||
```
|
```
|
||||||
|
|
||||||
```yaml tab="YAML"
|
```yaml tab="YAML"
|
||||||
|
@ -169,18 +163,19 @@ On subsequent requests, the client is forwarded to the same server.
|
||||||
services:
|
services:
|
||||||
my-service:
|
my-service:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
stickiness: {}
|
sticky:
|
||||||
|
cookie: {}
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Adding Stickiness with a Custom Cookie Name"
|
??? example "Adding Stickiness with custom Options"
|
||||||
|
|
||||||
```toml tab="TOML"
|
```toml tab="TOML"
|
||||||
[http.services]
|
[http.services]
|
||||||
[http.services.my-service]
|
[http.services.my-service]
|
||||||
[http.services.my-service.loadBalancer.stickiness]
|
[http.services.my-service.loadBalancer.sticky.cookie]
|
||||||
cookieName = "my_stickiness_cookie_name"
|
name = "my_sticky_cookie_name"
|
||||||
secureCookie = true
|
secure = true
|
||||||
httpOnlyCookie = true
|
httpOnly = true
|
||||||
```
|
```
|
||||||
|
|
||||||
```yaml tab="YAML"
|
```yaml tab="YAML"
|
||||||
|
@ -188,10 +183,11 @@ On subsequent requests, the client is forwarded to the same server.
|
||||||
services:
|
services:
|
||||||
my-service:
|
my-service:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
stickiness:
|
sticky:
|
||||||
cookieName: my_stickiness_cookie_name
|
cookie:
|
||||||
secureCookie: true
|
name: my_sticky_cookie_name
|
||||||
httpOnlyCookie: true
|
secure: true
|
||||||
|
httpOnly: true
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Health Check
|
#### Health Check
|
||||||
|
@ -306,6 +302,57 @@ Below are the available options for the health check mechanism:
|
||||||
My-Header: bar
|
My-Header: bar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Weighted Round Robin (service)
|
||||||
|
|
||||||
|
The WRR is able to load balance the requests between multiple services based on weights.
|
||||||
|
|
||||||
|
This strategy is only available to load balance between [services](./index.md) and not between [servers](./index.md#servers).
|
||||||
|
|
||||||
|
This strategy can be defined only with [File](../../providers/file.md).
|
||||||
|
|
||||||
|
```toml tab="TOML"
|
||||||
|
[http.services]
|
||||||
|
[http.services.canary]
|
||||||
|
[[http.services.canary.weighted.services]]
|
||||||
|
name = "appv1"
|
||||||
|
weight = 3
|
||||||
|
[[http.services.canary.weighted.services]]
|
||||||
|
name = "appv2"
|
||||||
|
weight = 1
|
||||||
|
|
||||||
|
[http.services.appv1]
|
||||||
|
[http.services.appv1.loadBalancer]
|
||||||
|
[[http.services.appv1.loadBalancer.servers]]
|
||||||
|
url = "http://private-ip-server-1/"
|
||||||
|
|
||||||
|
[http.services.appv2]
|
||||||
|
[http.services.appv2.loadBalancer]
|
||||||
|
[[http.services.appv2.loadBalancer.servers]]
|
||||||
|
url = "http://private-ip-server-2/"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="YAML"
|
||||||
|
http:
|
||||||
|
services:
|
||||||
|
canary:
|
||||||
|
weighted:
|
||||||
|
services:
|
||||||
|
- name: appv1
|
||||||
|
weight: 3
|
||||||
|
- name: appv2
|
||||||
|
weight: 1
|
||||||
|
|
||||||
|
appv1:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: "http://private-ip-server-1/"
|
||||||
|
|
||||||
|
appv2:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: "http://private-ip-server-2/"
|
||||||
|
```
|
||||||
|
|
||||||
## Configuring TCP Services
|
## Configuring TCP Services
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
|
|
||||||
[tcp.services.whoami-no-cert]
|
[tcp.services.whoami-no-cert]
|
||||||
[tcp.services.whoami-no-cert.loadBalancer]
|
[tcp.services.whoami-no-cert.loadBalancer]
|
||||||
method = "wrr"
|
|
||||||
[[tcp.services.whoami-no-cert.loadBalancer.servers]]
|
[[tcp.services.whoami-no-cert.loadBalancer.servers]]
|
||||||
address = "localhost:8083"
|
address = "localhost:8083"
|
||||||
|
|
||||||
|
|
38
integration/fixtures/wrr.toml
Normal file
38
integration/fixtures/wrr.toml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[api]
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
|
||||||
|
[entryPoints.web]
|
||||||
|
address = ":8000"
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
filename = "{{ .SelfFilename }}"
|
||||||
|
|
||||||
|
## dynamic configuration ##
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.router]
|
||||||
|
service = "wrr"
|
||||||
|
rule = "Path(`/whoami`)"
|
||||||
|
|
||||||
|
[http.services]
|
||||||
|
[[http.services.wrr.weighted.services]]
|
||||||
|
name = "service1"
|
||||||
|
weight = 3
|
||||||
|
[[http.services.wrr.weighted.services]]
|
||||||
|
name = "service2"
|
||||||
|
|
||||||
|
[http.services.service1.loadBalancer]
|
||||||
|
[[http.services.service1.loadBalancer.servers]]
|
||||||
|
url = "{{ .Server1 }}"
|
||||||
|
[http.services.service2.loadBalancer]
|
||||||
|
[[http.services.service2.loadBalancer.servers]]
|
||||||
|
url = "{{ .Server2 }}"
|
||||||
|
|
41
integration/fixtures/wrr_sticky.toml
Normal file
41
integration/fixtures/wrr_sticky.toml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[api]
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
|
||||||
|
[entryPoints.web]
|
||||||
|
address = ":8000"
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
filename = "{{ .SelfFilename }}"
|
||||||
|
|
||||||
|
## dynamic configuration ##
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.router]
|
||||||
|
service = "wrr"
|
||||||
|
rule = "Path(`/whoami`)"
|
||||||
|
|
||||||
|
[http.services]
|
||||||
|
[http.services.wrr.weighted.sticky.cookie]
|
||||||
|
name = "test"
|
||||||
|
|
||||||
|
[[http.services.wrr.weighted.services]]
|
||||||
|
name = "service1"
|
||||||
|
weight = 3
|
||||||
|
[[http.services.wrr.weighted.services]]
|
||||||
|
name = "service2"
|
||||||
|
weight = 1
|
||||||
|
|
||||||
|
[http.services.service1.loadBalancer]
|
||||||
|
[[http.services.service1.loadBalancer.servers]]
|
||||||
|
url = "{{ .Server1 }}"
|
||||||
|
[http.services.service2.loadBalancer]
|
||||||
|
[[http.services.service2.loadBalancer.servers]]
|
||||||
|
url = "{{ .Server2 }}"
|
|
@ -51,7 +51,7 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"service1": {
|
"service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
|
URL: "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
|
@ -563,7 +564,7 @@ func (s *SimpleSuite) TestServiceConfigErrors(c *check.C) {
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
defer cmd.Process.Kill()
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/services", 1000*time.Millisecond, try.BodyContains(`["the service \"service1@file\" doesn't have any load balancer"]`))
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/services", 1000*time.Millisecond, try.BodyContains(`["the service \"service1@file\" does not have any type defined"]`))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/services/service1@file", 1000*time.Millisecond, try.BodyContains(`"status":"disabled"`))
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/services/service1@file", 1000*time.Millisecond, try.BodyContains(`"status":"disabled"`))
|
||||||
|
@ -572,3 +573,101 @@ func (s *SimpleSuite) TestServiceConfigErrors(c *check.C) {
|
||||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/services/service2@file", 1000*time.Millisecond, try.BodyContains(`"status":"enabled"`))
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/services/service2@file", 1000*time.Millisecond, try.BodyContains(`"status":"enabled"`))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSuite) TestWRR(c *check.C) {
|
||||||
|
s.createComposeProject(c, "base")
|
||||||
|
s.composeProject.Start(c)
|
||||||
|
|
||||||
|
server1 := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||||
|
server2 := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||||
|
|
||||||
|
file := s.adaptFile(c, "fixtures/wrr.toml", struct {
|
||||||
|
Server1 string
|
||||||
|
Server2 string
|
||||||
|
}{Server1: "http://" + server1, Server2: "http://" + server2})
|
||||||
|
defer os.Remove(file)
|
||||||
|
|
||||||
|
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||||
|
defer output(c)
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/services", 1000*time.Millisecond, try.BodyContains("service1", "service2"))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
repartition := map[string]int{}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
response, err := http.DefaultClient.Do(req)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(response.Body)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
if strings.Contains(string(body), server1) {
|
||||||
|
repartition[server1]++
|
||||||
|
}
|
||||||
|
if strings.Contains(string(body), server2) {
|
||||||
|
repartition[server2]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Assert(repartition[server1], checker.Equals, 3)
|
||||||
|
c.Assert(repartition[server2], checker.Equals, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSuite) TestWRRSticky(c *check.C) {
|
||||||
|
s.createComposeProject(c, "base")
|
||||||
|
s.composeProject.Start(c)
|
||||||
|
|
||||||
|
server1 := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||||
|
server2 := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||||
|
|
||||||
|
file := s.adaptFile(c, "fixtures/wrr_sticky.toml", struct {
|
||||||
|
Server1 string
|
||||||
|
Server2 string
|
||||||
|
}{Server1: "http://" + server1, Server2: "http://" + server2})
|
||||||
|
defer os.Remove(file)
|
||||||
|
|
||||||
|
cmd, output := s.traefikCmd(withConfigFile(file))
|
||||||
|
defer output(c)
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/http/services", 1000*time.Millisecond, try.BodyContains("service1", "service2"))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
repartition := map[string]int{}
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
|
||||||
|
response, err := http.DefaultClient.Do(req)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
|
||||||
|
|
||||||
|
for _, cookie := range response.Cookies() {
|
||||||
|
req.AddCookie(cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(response.Body)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
if strings.Contains(string(body), server1) {
|
||||||
|
repartition[server1]++
|
||||||
|
}
|
||||||
|
if strings.Contains(string(body), server2) {
|
||||||
|
repartition[server2]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Assert(repartition[server1], checker.Equals, 4)
|
||||||
|
c.Assert(repartition[server2], checker.Equals, 0)
|
||||||
|
}
|
||||||
|
|
|
@ -203,7 +203,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
"bar@myprovider": func() *runtime.ServiceInfo {
|
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||||
si := &runtime.ServiceInfo{
|
si := &runtime.ServiceInfo{
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -219,7 +219,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
"baz@myprovider": func() *runtime.ServiceInfo {
|
"baz@myprovider": func() *runtime.ServiceInfo {
|
||||||
si := &runtime.ServiceInfo{
|
si := &runtime.ServiceInfo{
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.2",
|
URL: "http://127.0.0.2",
|
||||||
|
@ -248,7 +248,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
"bar@myprovider": func() *runtime.ServiceInfo {
|
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||||
si := &runtime.ServiceInfo{
|
si := &runtime.ServiceInfo{
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -264,7 +264,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
"baz@myprovider": func() *runtime.ServiceInfo {
|
"baz@myprovider": func() *runtime.ServiceInfo {
|
||||||
si := &runtime.ServiceInfo{
|
si := &runtime.ServiceInfo{
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.2",
|
URL: "http://127.0.0.2",
|
||||||
|
@ -280,7 +280,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
"test@myprovider": func() *runtime.ServiceInfo {
|
"test@myprovider": func() *runtime.ServiceInfo {
|
||||||
si := &runtime.ServiceInfo{
|
si := &runtime.ServiceInfo{
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.3",
|
URL: "http://127.0.0.3",
|
||||||
|
@ -309,7 +309,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
"bar@myprovider": func() *runtime.ServiceInfo {
|
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||||
si := &runtime.ServiceInfo{
|
si := &runtime.ServiceInfo{
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -337,7 +337,7 @@ func TestHandler_HTTP(t *testing.T) {
|
||||||
"bar@myprovider": func() *runtime.ServiceInfo {
|
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||||
si := &runtime.ServiceInfo{
|
si := &runtime.ServiceInfo{
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestHandler_Overview(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -63,7 +63,7 @@ func TestHandler_Overview(t *testing.T) {
|
||||||
},
|
},
|
||||||
"bar-service@myprovider": {
|
"bar-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -71,7 +71,7 @@ func TestHandler_Overview(t *testing.T) {
|
||||||
},
|
},
|
||||||
"fii-service@myprovider": {
|
"fii-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -37,7 +37,7 @@ func TestHandler_RawData(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
|
|
@ -404,8 +404,8 @@
|
||||||
[http.services.Service0]
|
[http.services.Service0]
|
||||||
[http.services.Service0.loadBalancer]
|
[http.services.Service0.loadBalancer]
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
[http.services.Service0.loadBalancer.stickiness]
|
[http.services.Service0.loadBalancer.sticky.cookie]
|
||||||
cookieName = "foobar"
|
name = "foobar"
|
||||||
|
|
||||||
[[http.services.Service0.loadBalancer.servers]]
|
[[http.services.Service0.loadBalancer.servers]]
|
||||||
url = "foobar"
|
url = "foobar"
|
||||||
|
|
|
@ -19,7 +19,8 @@ type HTTPConfiguration struct {
|
||||||
|
|
||||||
// Service holds a service configuration (can only be of one type at the same time).
|
// Service holds a service configuration (can only be of one type at the same time).
|
||||||
type Service struct {
|
type Service struct {
|
||||||
LoadBalancer *LoadBalancerService `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
|
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
|
||||||
|
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
@ -45,9 +46,47 @@ type RouterTLSConfig struct {
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
// LoadBalancerService holds the LoadBalancerService configuration.
|
// WeightedRoundRobin is a weighted round robin load-balancer of services.
|
||||||
type LoadBalancerService struct {
|
type WeightedRoundRobin struct {
|
||||||
Stickiness *Stickiness `json:"stickiness,omitempty" toml:"stickiness,omitempty" yaml:"stickiness,omitempty" label:"allowEmpty"`
|
Services []WRRService `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
|
||||||
|
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
|
// WRRService is a reference to a service load-balanced with weighted round robin.
|
||||||
|
type WRRService struct {
|
||||||
|
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaults Default values for a ServersLoadBalancer.
|
||||||
|
func (w *WRRService) SetDefaults() {
|
||||||
|
defaultWeight := 1
|
||||||
|
w.Weight = &defaultWeight
|
||||||
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
|
// Sticky holds the sticky configuration.
|
||||||
|
type Sticky struct {
|
||||||
|
Cookie *Cookie `json:"cookie,omitempty" toml:"cookie,omitempty" yaml:"cookie,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
|
// Cookie holds the sticky configuration based on cookie.
|
||||||
|
type Cookie struct {
|
||||||
|
Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Secure bool `json:"secure,omitempty" toml:"secure,omitempty" yaml:"secure,omitempty"`
|
||||||
|
HTTPOnly bool `json:"httpOnly,omitempty" toml:"httpOnly,omitempty" yaml:"httpOnly,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
|
// ServersLoadBalancer holds the ServersLoadBalancer configuration.
|
||||||
|
type ServersLoadBalancer struct {
|
||||||
|
Sticky *Sticky `json:"sticky,omitempty" toml:"sticky,omitempty" yaml:"sticky,omitempty" label:"allowEmpty"`
|
||||||
Servers []Server `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
|
Servers []Server `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
|
||||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty"`
|
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty"`
|
||||||
PassHostHeader bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
|
PassHostHeader bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
|
||||||
|
@ -55,7 +94,7 @@ type LoadBalancerService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mergeable tells if the given service is mergeable.
|
// Mergeable tells if the given service is mergeable.
|
||||||
func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool {
|
func (l *ServersLoadBalancer) Mergeable(loadBalancer *ServersLoadBalancer) bool {
|
||||||
savedServers := l.Servers
|
savedServers := l.Servers
|
||||||
defer func() {
|
defer func() {
|
||||||
l.Servers = savedServers
|
l.Servers = savedServers
|
||||||
|
@ -71,8 +110,8 @@ func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool
|
||||||
return reflect.DeepEqual(l, loadBalancer)
|
return reflect.DeepEqual(l, loadBalancer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaults Default values for a LoadBalancerService.
|
// SetDefaults Default values for a ServersLoadBalancer.
|
||||||
func (l *LoadBalancerService) SetDefaults() {
|
func (l *ServersLoadBalancer) SetDefaults() {
|
||||||
l.PassHostHeader = true
|
l.PassHostHeader = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,15 +124,6 @@ type ResponseForwarding struct {
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
// Stickiness holds the stickiness configuration.
|
|
||||||
type Stickiness struct {
|
|
||||||
CookieName string `json:"cookieName,omitempty" toml:"cookieName,omitempty" yaml:"cookieName,omitempty"`
|
|
||||||
SecureCookie bool `json:"secureCookie,omitempty" toml:"secureCookie,omitempty" yaml:"secureCookie,omitempty"`
|
|
||||||
HTTPOnlyCookie bool `json:"httpOnlyCookie,omitempty" toml:"httpOnlyCookie,omitempty" yaml:"httpOnlyCookie,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
|
||||||
|
|
||||||
// Server holds the server configuration.
|
// Server holds the server configuration.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"`
|
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"`
|
||||||
|
|
|
@ -45,7 +45,7 @@ type RouterTCPTLSConfig struct {
|
||||||
|
|
||||||
// TCPLoadBalancerService holds the LoadBalancerService configuration.
|
// TCPLoadBalancerService holds the LoadBalancerService configuration.
|
||||||
type TCPLoadBalancerService struct {
|
type TCPLoadBalancerService struct {
|
||||||
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" label-slice-as-struct:"server"`
|
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mergeable tells if the given service is mergeable.
|
// Mergeable tells if the given service is mergeable.
|
||||||
|
|
|
@ -247,6 +247,22 @@ func (in Configurations) DeepCopy() Configurations {
|
||||||
return *out
|
return *out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Cookie) DeepCopyInto(out *Cookie) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cookie.
|
||||||
|
func (in *Cookie) DeepCopy() *Cookie {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Cookie)
|
||||||
|
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 *DigestAuth) DeepCopyInto(out *DigestAuth) {
|
func (in *DigestAuth) DeepCopyInto(out *DigestAuth) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -508,42 +524,6 @@ func (in *IPWhiteList) DeepCopy() *IPWhiteList {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *LoadBalancerService) DeepCopyInto(out *LoadBalancerService) {
|
|
||||||
*out = *in
|
|
||||||
if in.Stickiness != nil {
|
|
||||||
in, out := &in.Stickiness, &out.Stickiness
|
|
||||||
*out = new(Stickiness)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
if in.Servers != nil {
|
|
||||||
in, out := &in.Servers, &out.Servers
|
|
||||||
*out = make([]Server, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.HealthCheck != nil {
|
|
||||||
in, out := &in.HealthCheck, &out.HealthCheck
|
|
||||||
*out = new(HealthCheck)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.ResponseForwarding != nil {
|
|
||||||
in, out := &in.ResponseForwarding, &out.ResponseForwarding
|
|
||||||
*out = new(ResponseForwarding)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancerService.
|
|
||||||
func (in *LoadBalancerService) DeepCopy() *LoadBalancerService {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(LoadBalancerService)
|
|
||||||
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 *MaxConn) DeepCopyInto(out *MaxConn) {
|
func (in *MaxConn) DeepCopyInto(out *MaxConn) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -954,12 +934,53 @@ func (in *Server) DeepCopy() *Server {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ServersLoadBalancer) DeepCopyInto(out *ServersLoadBalancer) {
|
||||||
|
*out = *in
|
||||||
|
if in.Sticky != nil {
|
||||||
|
in, out := &in.Sticky, &out.Sticky
|
||||||
|
*out = new(Sticky)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Servers != nil {
|
||||||
|
in, out := &in.Servers, &out.Servers
|
||||||
|
*out = make([]Server, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.HealthCheck != nil {
|
||||||
|
in, out := &in.HealthCheck, &out.HealthCheck
|
||||||
|
*out = new(HealthCheck)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.ResponseForwarding != nil {
|
||||||
|
in, out := &in.ResponseForwarding, &out.ResponseForwarding
|
||||||
|
*out = new(ResponseForwarding)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServersLoadBalancer.
|
||||||
|
func (in *ServersLoadBalancer) DeepCopy() *ServersLoadBalancer {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ServersLoadBalancer)
|
||||||
|
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 *Service) DeepCopyInto(out *Service) {
|
func (in *Service) DeepCopyInto(out *Service) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LoadBalancer != nil {
|
if in.LoadBalancer != nil {
|
||||||
in, out := &in.LoadBalancer, &out.LoadBalancer
|
in, out := &in.LoadBalancer, &out.LoadBalancer
|
||||||
*out = new(LoadBalancerService)
|
*out = new(ServersLoadBalancer)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Weighted != nil {
|
||||||
|
in, out := &in.Weighted, &out.Weighted
|
||||||
|
*out = new(WeightedRoundRobin)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -976,17 +997,22 @@ func (in *Service) DeepCopy() *Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 *Stickiness) DeepCopyInto(out *Stickiness) {
|
func (in *Sticky) DeepCopyInto(out *Sticky) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Cookie != nil {
|
||||||
|
in, out := &in.Cookie, &out.Cookie
|
||||||
|
*out = new(Cookie)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Stickiness.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sticky.
|
||||||
func (in *Stickiness) DeepCopy() *Stickiness {
|
func (in *Sticky) DeepCopy() *Sticky {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(Stickiness)
|
out := new(Sticky)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -1265,3 +1291,45 @@ func (in Users) DeepCopy() Users {
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return *out
|
return *out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *WRRService) DeepCopyInto(out *WRRService) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WRRService.
|
||||||
|
func (in *WRRService) DeepCopy() *WRRService {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(WRRService)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *WeightedRoundRobin) DeepCopyInto(out *WeightedRoundRobin) {
|
||||||
|
*out = *in
|
||||||
|
if in.Services != nil {
|
||||||
|
in, out := &in.Services, &out.Services
|
||||||
|
*out = make([]WRRService, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Sticky != nil {
|
||||||
|
in, out := &in.Sticky, &out.Sticky
|
||||||
|
*out = new(Sticky)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WeightedRoundRobin.
|
||||||
|
func (in *WeightedRoundRobin) DeepCopy() *WeightedRoundRobin {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(WeightedRoundRobin)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
|
@ -396,8 +396,8 @@
|
||||||
[http.services.Service0]
|
[http.services.Service0]
|
||||||
[http.services.Service0.loadBalancer]
|
[http.services.Service0.loadBalancer]
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
[http.services.Service0.loadBalancer.stickiness]
|
[http.services.Service0.loadBalancer.sticky.cookie]
|
||||||
cookieName = "foobar"
|
name = "foobar"
|
||||||
|
|
||||||
[[http.services.Service0.loadBalancer.servers]]
|
[[http.services.Service0.loadBalancer.servers]]
|
||||||
url = "foobar"
|
url = "foobar"
|
||||||
|
|
|
@ -142,8 +142,8 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
"traefik.http.services.Service0.loadbalancer.responseforwarding.flushinterval": "foobar",
|
"traefik.http.services.Service0.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||||
"traefik.http.services.Service0.loadbalancer.server.scheme": "foobar",
|
"traefik.http.services.Service0.loadbalancer.server.scheme": "foobar",
|
||||||
"traefik.http.services.Service0.loadbalancer.server.port": "8080",
|
"traefik.http.services.Service0.loadbalancer.server.port": "8080",
|
||||||
"traefik.http.services.Service0.loadbalancer.stickiness.cookiename": "foobar",
|
"traefik.http.services.Service0.loadbalancer.sticky.cookie.name": "foobar",
|
||||||
"traefik.http.services.Service0.loadbalancer.stickiness.securecookie": "true",
|
"traefik.http.services.Service0.loadbalancer.sticky.cookie.secure": "true",
|
||||||
"traefik.http.services.Service1.loadbalancer.healthcheck.headers.name0": "foobar",
|
"traefik.http.services.Service1.loadbalancer.healthcheck.headers.name0": "foobar",
|
||||||
"traefik.http.services.Service1.loadbalancer.healthcheck.headers.name1": "foobar",
|
"traefik.http.services.Service1.loadbalancer.healthcheck.headers.name1": "foobar",
|
||||||
"traefik.http.services.Service1.loadbalancer.healthcheck.hostname": "foobar",
|
"traefik.http.services.Service1.loadbalancer.healthcheck.hostname": "foobar",
|
||||||
|
@ -156,8 +156,8 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
"traefik.http.services.Service1.loadbalancer.responseforwarding.flushinterval": "foobar",
|
"traefik.http.services.Service1.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||||
"traefik.http.services.Service1.loadbalancer.server.scheme": "foobar",
|
"traefik.http.services.Service1.loadbalancer.server.scheme": "foobar",
|
||||||
"traefik.http.services.Service1.loadbalancer.server.port": "8080",
|
"traefik.http.services.Service1.loadbalancer.server.port": "8080",
|
||||||
"traefik.http.services.Service1.loadbalancer.stickiness": "false",
|
"traefik.http.services.Service1.loadbalancer.sticky": "false",
|
||||||
"traefik.http.services.Service1.loadbalancer.stickiness.cookiename": "fui",
|
"traefik.http.services.Service1.loadbalancer.sticky.cookie.name": "fui",
|
||||||
"traefik.tcp.routers.Router0.rule": "foobar",
|
"traefik.tcp.routers.Router0.rule": "foobar",
|
||||||
"traefik.tcp.routers.Router0.entrypoints": "foobar, fiibar",
|
"traefik.tcp.routers.Router0.entrypoints": "foobar, fiibar",
|
||||||
"traefik.tcp.routers.Router0.service": "foobar",
|
"traefik.tcp.routers.Router0.service": "foobar",
|
||||||
|
@ -510,11 +510,13 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service0": {
|
"Service0": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Stickiness: &dynamic.Stickiness{
|
Sticky: &dynamic.Sticky{
|
||||||
CookieName: "foobar",
|
Cookie: &dynamic.Cookie{
|
||||||
SecureCookie: true,
|
Name: "foobar",
|
||||||
HTTPOnlyCookie: false,
|
Secure: true,
|
||||||
|
HTTPOnly: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -541,7 +543,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
Scheme: "foobar",
|
Scheme: "foobar",
|
||||||
|
@ -908,10 +910,12 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service0": {
|
"Service0": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Stickiness: &dynamic.Stickiness{
|
Sticky: &dynamic.Sticky{
|
||||||
CookieName: "foobar",
|
Cookie: &dynamic.Cookie{
|
||||||
HTTPOnlyCookie: true,
|
Name: "foobar",
|
||||||
|
HTTPOnly: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -938,7 +942,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
Scheme: "foobar",
|
Scheme: "foobar",
|
||||||
|
@ -1101,9 +1105,9 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.ResponseForwarding.FlushInterval": "foobar",
|
"traefik.HTTP.Services.Service0.LoadBalancer.ResponseForwarding.FlushInterval": "foobar",
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.server.Port": "8080",
|
"traefik.HTTP.Services.Service0.LoadBalancer.server.Port": "8080",
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.server.Scheme": "foobar",
|
"traefik.HTTP.Services.Service0.LoadBalancer.server.Scheme": "foobar",
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.Stickiness.CookieName": "foobar",
|
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Name": "foobar",
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.Stickiness.HTTPOnlyCookie": "true",
|
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.HTTPOnly": "true",
|
||||||
"traefik.HTTP.Services.Service0.LoadBalancer.Stickiness.SecureCookie": "false",
|
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Secure": "false",
|
||||||
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name0": "foobar",
|
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name0": "foobar",
|
||||||
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name1": "foobar",
|
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name1": "foobar",
|
||||||
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Hostname": "foobar",
|
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Hostname": "foobar",
|
||||||
|
|
|
@ -43,7 +43,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{URL: "http://127.0.0.1:8085"},
|
{URL: "http://127.0.0.1:8085"},
|
||||||
{URL: "http://127.0.0.1:8086"},
|
{URL: "http://127.0.0.1:8086"},
|
||||||
|
@ -75,7 +75,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{URL: "http://127.0.0.1"},
|
{URL: "http://127.0.0.1"},
|
||||||
},
|
},
|
||||||
|
@ -149,7 +149,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:8085",
|
URL: "http://127.0.0.1:8085",
|
||||||
|
@ -167,7 +167,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
||||||
},
|
},
|
||||||
"bar-service@myprovider": {
|
"bar-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:8087",
|
URL: "http://127.0.0.1:8087",
|
||||||
|
@ -222,7 +222,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -293,7 +293,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -337,7 +337,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -389,7 +389,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
||||||
Services: map[string]*runtime.ServiceInfo{
|
Services: map[string]*runtime.ServiceInfo{
|
||||||
"foo-service@myprovider": {
|
"foo-service@myprovider": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
|
|
@ -99,7 +99,7 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, container dock
|
||||||
|
|
||||||
if len(configuration.Services) == 0 {
|
if len(configuration.Services) == 0 {
|
||||||
configuration.Services = make(map[string]*dynamic.Service)
|
configuration.Services = make(map[string]*dynamic.Service)
|
||||||
lb := &dynamic.LoadBalancerService{}
|
lb := &dynamic.ServersLoadBalancer{}
|
||||||
lb.SetDefaults()
|
lb.SetDefaults()
|
||||||
configuration.Services[serviceName] = &dynamic.Service{
|
configuration.Services[serviceName] = &dynamic.Service{
|
||||||
LoadBalancer: lb,
|
LoadBalancer: lb,
|
||||||
|
@ -171,7 +171,7 @@ func (p *Provider) addServerTCP(ctx context.Context, container dockerData, loadB
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) addServer(ctx context.Context, container dockerData, loadBalancer *dynamic.LoadBalancerService) error {
|
func (p *Provider) addServer(ctx context.Context, container dockerData, loadBalancer *dynamic.ServersLoadBalancer) error {
|
||||||
serverPort := getLBServerPort(loadBalancer)
|
serverPort := getLBServerPort(loadBalancer)
|
||||||
ip, port, err := p.getIPPort(ctx, container, serverPort)
|
ip, port, err := p.getIPPort(ctx, container, serverPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -291,7 +291,7 @@ func (p *Provider) getPortBinding(container dockerData, serverPort string) (*nat
|
||||||
return nil, fmt.Errorf("unable to find the external IP:Port for the container %q", container.Name)
|
return nil, fmt.Errorf("unable to find the external IP:Port for the container %q", container.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLBServerPort(loadBalancer *dynamic.LoadBalancerService) string {
|
func getLBServerPort(loadBalancer *dynamic.ServersLoadBalancer) string {
|
||||||
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
|
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
|
||||||
return loadBalancer.Servers[0].Port
|
return loadBalancer.Servers[0].Port
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func TestDefaultRule(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -105,7 +105,7 @@ func TestDefaultRule(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -156,7 +156,7 @@ func TestDefaultRule(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -200,7 +200,7 @@ func TestDefaultRule(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -244,7 +244,7 @@ func TestDefaultRule(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -293,7 +293,7 @@ func TestDefaultRule(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -376,7 +376,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -444,7 +444,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -454,7 +454,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Test2": {
|
"Test2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.2:80",
|
URL: "http://127.0.0.2:80",
|
||||||
|
@ -520,7 +520,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -573,7 +573,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -625,7 +625,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -669,7 +669,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -726,7 +726,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -773,7 +773,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -783,7 +783,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Service2": {
|
"Service2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -990,7 +990,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1042,7 +1042,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1127,7 +1127,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1200,7 +1200,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1292,7 +1292,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1363,7 +1363,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1450,7 +1450,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1526,7 +1526,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1592,7 +1592,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1602,7 +1602,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Test2": {
|
"Test2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.2:80",
|
URL: "http://127.0.0.2:80",
|
||||||
|
@ -1652,7 +1652,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1703,7 +1703,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "h2c://127.0.0.1:8080",
|
URL: "h2c://127.0.0.1:8080",
|
||||||
|
@ -1749,7 +1749,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -1759,7 +1759,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Service2": {
|
"Service2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:8080",
|
URL: "http://127.0.0.1:8080",
|
||||||
|
@ -1974,7 +1974,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -2035,7 +2035,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -2278,7 +2278,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
http:
|
http:
|
||||||
{{ range $i, $e := until 20 }}
|
|
||||||
routers:
|
routers:
|
||||||
|
{{ range $i, $e := until 20 }}
|
||||||
router{{ $e }}:
|
router{{ $e }}:
|
||||||
service: application-1
|
service: application-1
|
||||||
{{ end }}
|
{{ end }}
|
|
@ -0,0 +1,22 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`) && PathPrefix(`/foo`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 12
|
||||||
|
services:
|
||||||
|
- name: whoami
|
||||||
|
port: 80
|
||||||
|
weight: 10
|
||||||
|
- name: whoami2
|
||||||
|
port: 8080
|
||||||
|
weight: 0
|
||||||
|
|
|
@ -3,7 +3,6 @@ package crd
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -16,7 +15,6 @@ import (
|
||||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
"github.com/containous/traefik/v2/pkg/job"
|
"github.com/containous/traefik/v2/pkg/job"
|
||||||
"github.com/containous/traefik/v2/pkg/log"
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
"github.com/containous/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
|
||||||
"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"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
@ -136,159 +134,22 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkStringQuoteValidity(value string) error {
|
func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) *dynamic.Configuration {
|
||||||
_, err := strconv.Unquote(`"` + value + `"`)
|
tlsConfigs := make(map[string]*tls.CertAndStores)
|
||||||
return err
|
conf := &dynamic.Configuration{
|
||||||
}
|
HTTP: p.loadIngressRouteConfiguration(ctx, client, tlsConfigs),
|
||||||
|
TCP: p.loadIngressRouteTCPConfiguration(ctx, client, tlsConfigs),
|
||||||
func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([]dynamic.TCPServer, error) {
|
TLS: &dynamic.TLSConfiguration{
|
||||||
service, exists, err := client.GetService(namespace, svc.Name)
|
Certificates: getTLSConfig(tlsConfigs),
|
||||||
if err != nil {
|
Options: buildTLSOptions(ctx, client),
|
||||||
return nil, err
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !exists {
|
for _, middleware := range client.GetMiddlewares() {
|
||||||
return nil, errors.New("service not found")
|
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
||||||
}
|
}
|
||||||
|
|
||||||
var portSpec *corev1.ServicePort
|
return conf
|
||||||
for _, p := range service.Spec.Ports {
|
|
||||||
if svc.Port == p.Port {
|
|
||||||
portSpec = &p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if portSpec == nil {
|
|
||||||
return nil, errors.New("service port not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
var servers []dynamic.TCPServer
|
|
||||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
|
||||||
servers = append(servers, dynamic.TCPServer{
|
|
||||||
Address: fmt.Sprintf("%s:%d", service.Spec.ExternalName, portSpec.Port),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
|
||||||
if endpointsErr != nil {
|
|
||||||
return nil, endpointsErr
|
|
||||||
}
|
|
||||||
|
|
||||||
if !endpointsExists {
|
|
||||||
return nil, errors.New("endpoints not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(endpoints.Subsets) == 0 {
|
|
||||||
return nil, errors.New("subset not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
var port int32
|
|
||||||
for _, subset := range endpoints.Subsets {
|
|
||||||
for _, p := range subset.Ports {
|
|
||||||
if portSpec.Name == p.Name {
|
|
||||||
port = p.Port
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if port == 0 {
|
|
||||||
return nil, errors.New("cannot define a port")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range subset.Addresses {
|
|
||||||
servers = append(servers, dynamic.TCPServer{
|
|
||||||
Address: fmt.Sprintf("%s:%d", addr.IP, port),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return servers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]dynamic.Server, error) {
|
|
||||||
strategy := svc.Strategy
|
|
||||||
if strategy == "" {
|
|
||||||
strategy = "RoundRobin"
|
|
||||||
}
|
|
||||||
if strategy != "RoundRobin" {
|
|
||||||
return nil, fmt.Errorf("load balancing strategy %v is not supported", strategy)
|
|
||||||
}
|
|
||||||
|
|
||||||
service, exists, err := client.GetService(namespace, svc.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return nil, errors.New("service not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
var portSpec *corev1.ServicePort
|
|
||||||
for _, p := range service.Spec.Ports {
|
|
||||||
if svc.Port == p.Port {
|
|
||||||
portSpec = &p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if portSpec == nil {
|
|
||||||
return nil, errors.New("service port not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
var servers []dynamic.Server
|
|
||||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
|
||||||
servers = append(servers, dynamic.Server{
|
|
||||||
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
|
||||||
if endpointsErr != nil {
|
|
||||||
return nil, endpointsErr
|
|
||||||
}
|
|
||||||
|
|
||||||
if !endpointsExists {
|
|
||||||
return nil, errors.New("endpoints not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(endpoints.Subsets) == 0 {
|
|
||||||
return nil, errors.New("subset not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
var port int32
|
|
||||||
for _, subset := range endpoints.Subsets {
|
|
||||||
for _, p := range subset.Ports {
|
|
||||||
if portSpec.Name == p.Name {
|
|
||||||
port = p.Port
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if port == 0 {
|
|
||||||
return nil, errors.New("cannot define a port")
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol := "http"
|
|
||||||
switch svc.Scheme {
|
|
||||||
case "http", "https", "h2c":
|
|
||||||
protocol = svc.Scheme
|
|
||||||
case "":
|
|
||||||
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
|
|
||||||
protocol = "https"
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid scheme %q specified", svc.Scheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range subset.Addresses {
|
|
||||||
servers = append(servers, dynamic.Server{
|
|
||||||
URL: fmt.Sprintf("%s://%s:%d", protocol, addr.IP, port),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return servers, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options {
|
func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options {
|
||||||
|
@ -338,250 +199,9 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
|
||||||
return tlsOptions
|
return tlsOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.CertAndStores) *dynamic.HTTPConfiguration {
|
func checkStringQuoteValidity(value string) error {
|
||||||
conf := &dynamic.HTTPConfiguration{
|
_, err := strconv.Unquote(`"` + value + `"`)
|
||||||
Routers: map[string]*dynamic.Router{},
|
return err
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
|
||||||
Services: map[string]*dynamic.Service{},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ingressRoute := range client.GetIngressRoutes() {
|
|
||||||
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRoute.Name), log.Str("namespace", ingressRoute.Namespace)))
|
|
||||||
|
|
||||||
// TODO keep the name ingressClass?
|
|
||||||
if !shouldProcessIngress(p.IngressClass, ingressRoute.Annotations[annotationKubernetesIngressClass]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err := getTLSHTTP(ctx, ingressRoute, client, tlsConfigs)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("Error configuring TLS: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ingressName := ingressRoute.Name
|
|
||||||
if len(ingressName) == 0 {
|
|
||||||
ingressName = ingressRoute.GenerateName
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, route := range ingressRoute.Spec.Routes {
|
|
||||||
if route.Kind != "Rule" {
|
|
||||||
logger.Errorf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(route.Match) == 0 {
|
|
||||||
logger.Errorf("Empty match rule")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkStringQuoteValidity(route.Match); err != nil {
|
|
||||||
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var allServers []dynamic.Server
|
|
||||||
for _, service := range route.Services {
|
|
||||||
servers, err := loadServers(client, ingressRoute.Namespace, service)
|
|
||||||
if err != nil {
|
|
||||||
logger.
|
|
||||||
WithField("serviceName", service.Name).
|
|
||||||
WithField("servicePort", service.Port).
|
|
||||||
Errorf("Cannot create service: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
allServers = append(allServers, servers...)
|
|
||||||
}
|
|
||||||
|
|
||||||
var mds []string
|
|
||||||
for _, mi := range route.Middlewares {
|
|
||||||
if strings.Contains(mi.Name, "@") {
|
|
||||||
if len(mi.Namespace) > 0 {
|
|
||||||
logger.
|
|
||||||
WithField(log.MiddlewareName, mi.Name).
|
|
||||||
Warnf("namespace %q is ignored in cross-provider context", mi.Namespace)
|
|
||||||
}
|
|
||||||
mds = append(mds, mi.Name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ns := mi.Namespace
|
|
||||||
if len(ns) == 0 {
|
|
||||||
ns = ingressRoute.Namespace
|
|
||||||
}
|
|
||||||
mds = append(mds, makeID(ns, mi.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := makeServiceKey(route.Match, ingressName)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceName := makeID(ingressRoute.Namespace, key)
|
|
||||||
|
|
||||||
conf.Routers[serviceName] = &dynamic.Router{
|
|
||||||
Middlewares: mds,
|
|
||||||
Priority: route.Priority,
|
|
||||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
|
||||||
Rule: route.Match,
|
|
||||||
Service: serviceName,
|
|
||||||
}
|
|
||||||
|
|
||||||
if ingressRoute.Spec.TLS != nil {
|
|
||||||
tlsConf := &dynamic.RouterTLSConfig{
|
|
||||||
CertResolver: ingressRoute.Spec.TLS.CertResolver,
|
|
||||||
}
|
|
||||||
|
|
||||||
if ingressRoute.Spec.TLS.Options != nil && len(ingressRoute.Spec.TLS.Options.Name) > 0 {
|
|
||||||
tlsOptionsName := ingressRoute.Spec.TLS.Options.Name
|
|
||||||
// Is a Kubernetes CRD reference, (i.e. not a cross-provider reference)
|
|
||||||
ns := ingressRoute.Spec.TLS.Options.Namespace
|
|
||||||
if !strings.Contains(tlsOptionsName, "@") {
|
|
||||||
if len(ns) == 0 {
|
|
||||||
ns = ingressRoute.Namespace
|
|
||||||
}
|
|
||||||
tlsOptionsName = makeID(ns, tlsOptionsName)
|
|
||||||
} else if len(ns) > 0 {
|
|
||||||
logger.
|
|
||||||
WithField("TLSoptions", ingressRoute.Spec.TLS.Options.Name).
|
|
||||||
Warnf("namespace %q is ignored in cross-provider context", ns)
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsConf.Options = tlsOptionsName
|
|
||||||
}
|
|
||||||
conf.Routers[serviceName].TLS = tlsConf
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.Services[serviceName] = &dynamic.Service{
|
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
|
||||||
Servers: allServers,
|
|
||||||
// TODO: support other strategies.
|
|
||||||
PassHostHeader: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return conf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.CertAndStores) *dynamic.TCPConfiguration {
|
|
||||||
conf := &dynamic.TCPConfiguration{
|
|
||||||
Routers: map[string]*dynamic.TCPRouter{},
|
|
||||||
Services: map[string]*dynamic.TCPService{},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ingressRouteTCP := range client.GetIngressRouteTCPs() {
|
|
||||||
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRouteTCP.Name), log.Str("namespace", ingressRouteTCP.Namespace)))
|
|
||||||
|
|
||||||
if !shouldProcessIngress(p.IngressClass, ingressRouteTCP.Annotations[annotationKubernetesIngressClass]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if ingressRouteTCP.Spec.TLS != nil && !ingressRouteTCP.Spec.TLS.Passthrough {
|
|
||||||
err := getTLSTCP(ctx, ingressRouteTCP, client, tlsConfigs)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("Error configuring TLS: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ingressName := ingressRouteTCP.Name
|
|
||||||
if len(ingressName) == 0 {
|
|
||||||
ingressName = ingressRouteTCP.GenerateName
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, route := range ingressRouteTCP.Spec.Routes {
|
|
||||||
if len(route.Match) == 0 {
|
|
||||||
logger.Errorf("Empty match rule")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkStringQuoteValidity(route.Match); err != nil {
|
|
||||||
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var allServers []dynamic.TCPServer
|
|
||||||
for _, service := range route.Services {
|
|
||||||
servers, err := loadTCPServers(client, ingressRouteTCP.Namespace, service)
|
|
||||||
if err != nil {
|
|
||||||
logger.
|
|
||||||
WithField("serviceName", service.Name).
|
|
||||||
WithField("servicePort", service.Port).
|
|
||||||
Errorf("Cannot create service: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
allServers = append(allServers, servers...)
|
|
||||||
}
|
|
||||||
|
|
||||||
key, e := makeServiceKey(route.Match, ingressName)
|
|
||||||
if e != nil {
|
|
||||||
logger.Error(e)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceName := makeID(ingressRouteTCP.Namespace, key)
|
|
||||||
conf.Routers[serviceName] = &dynamic.TCPRouter{
|
|
||||||
EntryPoints: ingressRouteTCP.Spec.EntryPoints,
|
|
||||||
Rule: route.Match,
|
|
||||||
Service: serviceName,
|
|
||||||
}
|
|
||||||
|
|
||||||
if ingressRouteTCP.Spec.TLS != nil {
|
|
||||||
conf.Routers[serviceName].TLS = &dynamic.RouterTCPTLSConfig{
|
|
||||||
Passthrough: ingressRouteTCP.Spec.TLS.Passthrough,
|
|
||||||
CertResolver: ingressRouteTCP.Spec.TLS.CertResolver,
|
|
||||||
}
|
|
||||||
|
|
||||||
if ingressRouteTCP.Spec.TLS.Options != nil && len(ingressRouteTCP.Spec.TLS.Options.Name) > 0 {
|
|
||||||
tlsOptionsName := ingressRouteTCP.Spec.TLS.Options.Name
|
|
||||||
// Is a Kubernetes CRD reference (i.e. not a cross-provider reference)
|
|
||||||
ns := ingressRouteTCP.Spec.TLS.Options.Namespace
|
|
||||||
if !strings.Contains(tlsOptionsName, "@") {
|
|
||||||
if len(ns) == 0 {
|
|
||||||
ns = ingressRouteTCP.Namespace
|
|
||||||
}
|
|
||||||
tlsOptionsName = makeID(ns, tlsOptionsName)
|
|
||||||
} else if len(ns) > 0 {
|
|
||||||
logger.
|
|
||||||
WithField("TLSoptions", ingressRouteTCP.Spec.TLS.Options.Name).
|
|
||||||
Warnf("namespace %q is ignored in cross-provider context", ns)
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.Routers[serviceName].TLS.Options = tlsOptionsName
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.Services[serviceName] = &dynamic.TCPService{
|
|
||||||
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
|
||||||
Servers: allServers,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return conf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) *dynamic.Configuration {
|
|
||||||
tlsConfigs := make(map[string]*tls.CertAndStores)
|
|
||||||
conf := &dynamic.Configuration{
|
|
||||||
HTTP: p.loadIngressRouteConfiguration(ctx, client, tlsConfigs),
|
|
||||||
TCP: p.loadIngressRouteTCPConfiguration(ctx, client, tlsConfigs),
|
|
||||||
TLS: &dynamic.TLSConfiguration{
|
|
||||||
Certificates: getTLSConfig(tlsConfigs),
|
|
||||||
Options: buildTLSOptions(ctx, client),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, middleware := range client.GetMiddlewares() {
|
|
||||||
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
|
||||||
}
|
|
||||||
|
|
||||||
return conf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeServiceKey(rule, ingressName string) (string, error) {
|
func makeServiceKey(rule, ingressName string) (string, error) {
|
||||||
|
@ -608,50 +228,6 @@ func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bo
|
||||||
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
|
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTLSHTTP(ctx context.Context, ingressRoute *v1alpha1.IngressRoute, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
|
|
||||||
if ingressRoute.Spec.TLS == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if ingressRoute.Spec.TLS.SecretName == "" {
|
|
||||||
log.FromContext(ctx).Debugf("Skipping TLS sub-section: No secret name provided")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
|
||||||
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
|
||||||
tlsConf, err := getTLS(k8sClient, ingressRoute.Spec.TLS.SecretName, ingressRoute.Namespace)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsConfigs[configKey] = tlsConf
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTLSTCP(ctx context.Context, ingressRoute *v1alpha1.IngressRouteTCP, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
|
|
||||||
if ingressRoute.Spec.TLS == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if ingressRoute.Spec.TLS.SecretName == "" {
|
|
||||||
log.FromContext(ctx).Debugf("Skipping TLS sub-section for TCP: No secret name provided")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
|
||||||
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
|
||||||
tlsConf, err := getTLS(k8sClient, ingressRoute.Spec.TLS.SecretName, ingressRoute.Namespace)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsConfigs[configKey] = tlsConf
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTLS(k8sClient Client, secretName, namespace string) (*tls.CertAndStores, error) {
|
func getTLS(k8sClient Client, secretName, namespace string) (*tls.CertAndStores, error) {
|
||||||
secret, exists, err := k8sClient.GetSecret(namespace, secretName)
|
secret, exists, err := k8sClient.GetSecret(namespace, secretName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
274
pkg/provider/kubernetes/crd/kubernetes_http.go
Normal file
274
pkg/provider/kubernetes/crd/kubernetes_http.go
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
package crd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
|
"github.com/containous/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||||
|
"github.com/containous/traefik/v2/pkg/tls"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.CertAndStores) *dynamic.HTTPConfiguration {
|
||||||
|
conf := &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ingressRoute := range client.GetIngressRoutes() {
|
||||||
|
ctxRt := log.With(ctx, log.Str("ingress", ingressRoute.Name), log.Str("namespace", ingressRoute.Namespace))
|
||||||
|
logger := log.FromContext(ctxRt)
|
||||||
|
|
||||||
|
// TODO keep the name ingressClass?
|
||||||
|
if !shouldProcessIngress(p.IngressClass, ingressRoute.Annotations[annotationKubernetesIngressClass]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err := getTLSHTTP(ctx, ingressRoute, client, tlsConfigs)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Error configuring TLS: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ingressName := ingressRoute.Name
|
||||||
|
if len(ingressName) == 0 {
|
||||||
|
ingressName = ingressRoute.GenerateName
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, route := range ingressRoute.Spec.Routes {
|
||||||
|
if route.Kind != "Rule" {
|
||||||
|
logger.Errorf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(route.Match) == 0 {
|
||||||
|
logger.Errorf("Empty match rule")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkStringQuoteValidity(route.Match); err != nil {
|
||||||
|
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := makeServiceKey(route.Match, ingressName)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceName := makeID(ingressRoute.Namespace, key)
|
||||||
|
|
||||||
|
for _, service := range route.Services {
|
||||||
|
balancerServerHTTP, err := createLoadBalancerServerHTTP(client, ingressRoute, service)
|
||||||
|
if err != nil {
|
||||||
|
logger.
|
||||||
|
WithField("serviceName", service.Name).
|
||||||
|
WithField("servicePort", service.Port).
|
||||||
|
Errorf("Cannot create service: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(route.Services) == 1 {
|
||||||
|
conf.Services[serviceName] = balancerServerHTTP
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceKey := fmt.Sprintf("%s-%s-%d", serviceName, service.Name, service.Port)
|
||||||
|
conf.Services[serviceKey] = balancerServerHTTP
|
||||||
|
|
||||||
|
srv := dynamic.WRRService{Name: serviceKey}
|
||||||
|
srv.SetDefaults()
|
||||||
|
if service.Weight != nil {
|
||||||
|
srv.Weight = service.Weight
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.Services[serviceName] == nil {
|
||||||
|
conf.Services[serviceName] = &dynamic.Service{Weighted: &dynamic.WeightedRoundRobin{}}
|
||||||
|
}
|
||||||
|
conf.Services[serviceName].Weighted.Services = append(conf.Services[serviceName].Weighted.Services, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mds []string
|
||||||
|
for _, mi := range route.Middlewares {
|
||||||
|
if strings.Contains(mi.Name, "@") {
|
||||||
|
if len(mi.Namespace) > 0 {
|
||||||
|
logger.
|
||||||
|
WithField(log.MiddlewareName, mi.Name).
|
||||||
|
Warnf("namespace %q is ignored in cross-provider context", mi.Namespace)
|
||||||
|
}
|
||||||
|
mds = append(mds, mi.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ns := mi.Namespace
|
||||||
|
if len(ns) == 0 {
|
||||||
|
ns = ingressRoute.Namespace
|
||||||
|
}
|
||||||
|
mds = append(mds, makeID(ns, mi.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.Routers[serviceName] = &dynamic.Router{
|
||||||
|
Middlewares: mds,
|
||||||
|
Priority: route.Priority,
|
||||||
|
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||||
|
Rule: route.Match,
|
||||||
|
Service: serviceName,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ingressRoute.Spec.TLS != nil {
|
||||||
|
tlsConf := &dynamic.RouterTLSConfig{
|
||||||
|
CertResolver: ingressRoute.Spec.TLS.CertResolver,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ingressRoute.Spec.TLS.Options != nil && len(ingressRoute.Spec.TLS.Options.Name) > 0 {
|
||||||
|
tlsOptionsName := ingressRoute.Spec.TLS.Options.Name
|
||||||
|
// Is a Kubernetes CRD reference, (i.e. not a cross-provider reference)
|
||||||
|
ns := ingressRoute.Spec.TLS.Options.Namespace
|
||||||
|
if !strings.Contains(tlsOptionsName, "@") {
|
||||||
|
if len(ns) == 0 {
|
||||||
|
ns = ingressRoute.Namespace
|
||||||
|
}
|
||||||
|
tlsOptionsName = makeID(ns, tlsOptionsName)
|
||||||
|
} else if len(ns) > 0 {
|
||||||
|
logger.
|
||||||
|
WithField("TLSoptions", ingressRoute.Spec.TLS.Options.Name).
|
||||||
|
Warnf("namespace %q is ignored in cross-provider context", ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConf.Options = tlsOptionsName
|
||||||
|
}
|
||||||
|
conf.Routers[serviceName].TLS = tlsConf
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLoadBalancerServerHTTP(client Client, ingressRoute *v1alpha1.IngressRoute, service v1alpha1.Service) (*dynamic.Service, error) {
|
||||||
|
servers, err := loadServers(client, ingressRoute.Namespace, service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dynamic.Service{
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: servers,
|
||||||
|
// TODO: support other strategies.
|
||||||
|
PassHostHeader: true,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]dynamic.Server, error) {
|
||||||
|
strategy := svc.Strategy
|
||||||
|
if strategy == "" {
|
||||||
|
strategy = "RoundRobin"
|
||||||
|
}
|
||||||
|
if strategy != "RoundRobin" {
|
||||||
|
return nil, fmt.Errorf("load balancing strategy %v is not supported", strategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
service, exists, err := client.GetService(namespace, svc.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return nil, errors.New("service not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var portSpec *corev1.ServicePort
|
||||||
|
for _, p := range service.Spec.Ports {
|
||||||
|
if svc.Port == p.Port {
|
||||||
|
portSpec = &p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if portSpec == nil {
|
||||||
|
return nil, errors.New("service port not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var servers []dynamic.Server
|
||||||
|
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||||
|
servers = append(servers, dynamic.Server{
|
||||||
|
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||||
|
if endpointsErr != nil {
|
||||||
|
return nil, endpointsErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if !endpointsExists {
|
||||||
|
return nil, errors.New("endpoints not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(endpoints.Subsets) == 0 {
|
||||||
|
return nil, errors.New("subset not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var port int32
|
||||||
|
for _, subset := range endpoints.Subsets {
|
||||||
|
for _, p := range subset.Ports {
|
||||||
|
if portSpec.Name == p.Name {
|
||||||
|
port = p.Port
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if port == 0 {
|
||||||
|
return nil, errors.New("cannot define a port")
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol := "http"
|
||||||
|
switch svc.Scheme {
|
||||||
|
case "http", "https", "h2c":
|
||||||
|
protocol = svc.Scheme
|
||||||
|
case "":
|
||||||
|
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
|
||||||
|
protocol = "https"
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid scheme %q specified", svc.Scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range subset.Addresses {
|
||||||
|
servers = append(servers, dynamic.Server{
|
||||||
|
URL: fmt.Sprintf("%s://%s:%d", protocol, addr.IP, port),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return servers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTLSHTTP(ctx context.Context, ingressRoute *v1alpha1.IngressRoute, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
|
||||||
|
if ingressRoute.Spec.TLS == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ingressRoute.Spec.TLS.SecretName == "" {
|
||||||
|
log.FromContext(ctx).Debugf("No secret name provided")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
||||||
|
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
||||||
|
tlsConf, err := getTLS(k8sClient, ingressRoute.Spec.TLS.SecretName, ingressRoute.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfigs[configKey] = tlsConf
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
201
pkg/provider/kubernetes/crd/kubernetes_tcp.go
Normal file
201
pkg/provider/kubernetes/crd/kubernetes_tcp.go
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
package crd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
|
"github.com/containous/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||||
|
"github.com/containous/traefik/v2/pkg/tls"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.CertAndStores) *dynamic.TCPConfiguration {
|
||||||
|
conf := &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{},
|
||||||
|
Services: map[string]*dynamic.TCPService{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ingressRouteTCP := range client.GetIngressRouteTCPs() {
|
||||||
|
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRouteTCP.Name), log.Str("namespace", ingressRouteTCP.Namespace)))
|
||||||
|
|
||||||
|
if !shouldProcessIngress(p.IngressClass, ingressRouteTCP.Annotations[annotationKubernetesIngressClass]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ingressRouteTCP.Spec.TLS != nil && !ingressRouteTCP.Spec.TLS.Passthrough {
|
||||||
|
err := getTLSTCP(ctx, ingressRouteTCP, client, tlsConfigs)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Error configuring TLS: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ingressName := ingressRouteTCP.Name
|
||||||
|
if len(ingressName) == 0 {
|
||||||
|
ingressName = ingressRouteTCP.GenerateName
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, route := range ingressRouteTCP.Spec.Routes {
|
||||||
|
if len(route.Match) == 0 {
|
||||||
|
logger.Errorf("Empty match rule")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkStringQuoteValidity(route.Match); err != nil {
|
||||||
|
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var allServers []dynamic.TCPServer
|
||||||
|
for _, service := range route.Services {
|
||||||
|
servers, err := loadTCPServers(client, ingressRouteTCP.Namespace, service)
|
||||||
|
if err != nil {
|
||||||
|
logger.
|
||||||
|
WithField("serviceName", service.Name).
|
||||||
|
WithField("servicePort", service.Port).
|
||||||
|
Errorf("Cannot create service: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
allServers = append(allServers, servers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, e := makeServiceKey(route.Match, ingressName)
|
||||||
|
if e != nil {
|
||||||
|
logger.Error(e)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceName := makeID(ingressRouteTCP.Namespace, key)
|
||||||
|
conf.Routers[serviceName] = &dynamic.TCPRouter{
|
||||||
|
EntryPoints: ingressRouteTCP.Spec.EntryPoints,
|
||||||
|
Rule: route.Match,
|
||||||
|
Service: serviceName,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ingressRouteTCP.Spec.TLS != nil {
|
||||||
|
conf.Routers[serviceName].TLS = &dynamic.RouterTCPTLSConfig{
|
||||||
|
Passthrough: ingressRouteTCP.Spec.TLS.Passthrough,
|
||||||
|
CertResolver: ingressRouteTCP.Spec.TLS.CertResolver,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ingressRouteTCP.Spec.TLS.Options != nil && len(ingressRouteTCP.Spec.TLS.Options.Name) > 0 {
|
||||||
|
tlsOptionsName := ingressRouteTCP.Spec.TLS.Options.Name
|
||||||
|
// Is a Kubernetes CRD reference (i.e. not a cross-provider reference)
|
||||||
|
ns := ingressRouteTCP.Spec.TLS.Options.Namespace
|
||||||
|
if !strings.Contains(tlsOptionsName, "@") {
|
||||||
|
if len(ns) == 0 {
|
||||||
|
ns = ingressRouteTCP.Namespace
|
||||||
|
}
|
||||||
|
tlsOptionsName = makeID(ns, tlsOptionsName)
|
||||||
|
} else if len(ns) > 0 {
|
||||||
|
logger.
|
||||||
|
WithField("TLSoptions", ingressRouteTCP.Spec.TLS.Options.Name).
|
||||||
|
Warnf("namespace %q is ignored in cross-provider context", ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.Routers[serviceName].TLS.Options = tlsOptionsName
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.Services[serviceName] = &dynamic.TCPService{
|
||||||
|
LoadBalancer: &dynamic.TCPLoadBalancerService{
|
||||||
|
Servers: allServers,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([]dynamic.TCPServer, error) {
|
||||||
|
service, exists, err := client.GetService(namespace, svc.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return nil, errors.New("service not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var portSpec *corev1.ServicePort
|
||||||
|
for _, p := range service.Spec.Ports {
|
||||||
|
if svc.Port == p.Port {
|
||||||
|
portSpec = &p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if portSpec == nil {
|
||||||
|
return nil, errors.New("service port not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var servers []dynamic.TCPServer
|
||||||
|
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||||
|
servers = append(servers, dynamic.TCPServer{
|
||||||
|
Address: fmt.Sprintf("%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||||
|
if endpointsErr != nil {
|
||||||
|
return nil, endpointsErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if !endpointsExists {
|
||||||
|
return nil, errors.New("endpoints not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(endpoints.Subsets) == 0 {
|
||||||
|
return nil, errors.New("subset not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var port int32
|
||||||
|
for _, subset := range endpoints.Subsets {
|
||||||
|
for _, p := range subset.Ports {
|
||||||
|
if portSpec.Name == p.Name {
|
||||||
|
port = p.Port
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if port == 0 {
|
||||||
|
return nil, errors.New("cannot define a port")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range subset.Addresses {
|
||||||
|
servers = append(servers, dynamic.TCPServer{
|
||||||
|
Address: fmt.Sprintf("%s:%d", addr.IP, port),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return servers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTLSTCP(ctx context.Context, ingressRoute *v1alpha1.IngressRouteTCP, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
|
||||||
|
if ingressRoute.Spec.TLS == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ingressRoute.Spec.TLS.SecretName == "" {
|
||||||
|
log.FromContext(ctx).Debugf("No secret name provided")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
||||||
|
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
||||||
|
tlsConf, err := getTLS(k8sClient, ingressRoute.Spec.TLS.SecretName, ingressRoute.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfigs[configKey] = tlsConf
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -12,6 +12,8 @@ import (
|
||||||
|
|
||||||
var _ provider.Provider = (*Provider)(nil)
|
var _ provider.Provider = (*Provider)(nil)
|
||||||
|
|
||||||
|
func Int(v int) *int { return &v }
|
||||||
|
|
||||||
func TestLoadIngressRouteTCPs(t *testing.T) {
|
func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
@ -671,7 +673,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -720,7 +722,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test2.route-23c7f4c450289ee29016": {
|
"default/test2.route-23c7f4c450289ee29016": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -770,7 +772,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test2.route-23c7f4c450289ee29016": {
|
"default/test2.route-23c7f4c450289ee29016": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -812,7 +814,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -825,7 +827,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"default/test.route-77c62dfe9517144aeeaa": {
|
"default/test.route-77c62dfe9517144aeeaa": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -843,7 +845,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "One ingress Route with two different services, their servers will merge",
|
desc: "One ingress Route with two different services",
|
||||||
paths: []string{"services.yml", "with_two_services.yml"},
|
paths: []string{"services.yml", "with_two_services.yml"},
|
||||||
expected: &dynamic.Configuration{
|
expected: &dynamic.Configuration{
|
||||||
TLS: &dynamic.TLSConfiguration{},
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
@ -863,7 +865,21 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-77c62dfe9517144aeeaa": {
|
"default/test.route-77c62dfe9517144aeeaa": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
Weighted: &dynamic.WeightedRoundRobin{
|
||||||
|
Services: []dynamic.WRRService{
|
||||||
|
{
|
||||||
|
Name: "default/test.route-77c62dfe9517144aeeaa-whoami-80",
|
||||||
|
Weight: func(i int) *int { return &i }(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "default/test.route-77c62dfe9517144aeeaa-whoami2-8080",
|
||||||
|
Weight: func(i int) *int { return &i }(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"default/test.route-77c62dfe9517144aeeaa-whoami-80": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -871,6 +887,77 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.2:80",
|
URL: "http://10.10.0.2:80",
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"default/test.route-77c62dfe9517144aeeaa-whoami2-8080": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.3:8080",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.4:8080",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "One ingress Route with two different services, with weights",
|
||||||
|
paths: []string{"services.yml", "with_two_services_weight.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{},
|
||||||
|
Services: map[string]*dynamic.TCPService{},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"default/test.route-77c62dfe9517144aeeaa": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "default/test.route-77c62dfe9517144aeeaa",
|
||||||
|
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
|
||||||
|
Priority: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{
|
||||||
|
"default/test.route-77c62dfe9517144aeeaa": {
|
||||||
|
Weighted: &dynamic.WeightedRoundRobin{
|
||||||
|
Services: []dynamic.WRRService{
|
||||||
|
{
|
||||||
|
Name: "default/test.route-77c62dfe9517144aeeaa-whoami-80",
|
||||||
|
Weight: Int(10),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "default/test.route-77c62dfe9517144aeeaa-whoami2-8080",
|
||||||
|
Weight: Int(0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"default/test.route-77c62dfe9517144aeeaa-whoami-80": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.1:80",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.2:80",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"default/test.route-77c62dfe9517144aeeaa-whoami2-8080": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.3:8080",
|
URL: "http://10.10.0.3:8080",
|
||||||
},
|
},
|
||||||
|
@ -981,7 +1068,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -1039,7 +1126,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -1097,7 +1184,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -1154,7 +1241,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -1200,7 +1287,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -1246,7 +1333,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -1284,7 +1371,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://10.10.0.1:80",
|
URL: "http://10.10.0.1:80",
|
||||||
|
@ -1321,7 +1408,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "https://10.10.0.5:8443",
|
URL: "https://10.10.0.5:8443",
|
||||||
|
@ -1358,7 +1445,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default/test.route-6b204d94623b3df4370c": {
|
"default/test.route-6b204d94623b3df4370c": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "https://10.10.0.7:8443",
|
URL: "https://10.10.0.7:8443",
|
||||||
|
|
|
@ -49,6 +49,7 @@ type Service struct {
|
||||||
Scheme string `json:"scheme,omitempty"`
|
Scheme string `json:"scheme,omitempty"`
|
||||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty"`
|
HealthCheck *HealthCheck `json:"healthCheck,omitempty"`
|
||||||
Strategy string `json:"strategy,omitempty"`
|
Strategy string `json:"strategy,omitempty"`
|
||||||
|
Weight *int `json:"weight,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MiddlewareRef is a ref to the Middleware resources.
|
// MiddlewareRef is a ref to the Middleware resources.
|
||||||
|
|
|
@ -395,6 +395,11 @@ func (in *Service) DeepCopyInto(out *Service) {
|
||||||
*out = new(HealthCheck)
|
*out = new(HealthCheck)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
|
if in.Weight != nil {
|
||||||
|
in, out := &in.Weight, &out.Weight
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,7 +229,7 @@ func loadService(client Client, namespace string, backend v1beta1.IngressBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
return &dynamic.Service{
|
return &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: servers,
|
Servers: servers,
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,7 +50,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -84,7 +84,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -118,7 +118,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -148,7 +148,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -177,7 +177,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/example-com/80": {
|
"testing/example-com/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -208,7 +208,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -242,7 +242,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -276,7 +276,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -317,7 +317,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -362,7 +362,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -375,7 +375,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"testing/service2/8082": {
|
"testing/service2/8082": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -428,7 +428,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default-backend": {
|
"default-backend": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -458,7 +458,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -488,7 +488,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/tchouk": {
|
"testing/service1/tchouk": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -518,7 +518,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/tchouk": {
|
"testing/service1/tchouk": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -552,7 +552,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/tchouk": {
|
"testing/service1/tchouk": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -565,7 +565,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"testing/service1/carotte": {
|
"testing/service1/carotte": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -599,7 +599,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/tchouk": {
|
"testing/service1/tchouk": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -612,7 +612,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"toto/service1/tchouk": {
|
"toto/service1/tchouk": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -664,7 +664,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/8080": {
|
"testing/service1/8080": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -696,7 +696,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/example-com/80": {
|
"testing/example-com/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -733,7 +733,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/443": {
|
"testing/service1/443": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -763,7 +763,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/8443": {
|
"testing/service1/8443": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -794,7 +794,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/8443": {
|
"testing/service1/8443": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -825,7 +825,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"default-backend": {
|
"default-backend": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -855,7 +855,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"testing/service1/80": {
|
"testing/service1/80": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
|
|
@ -98,7 +98,7 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, app marathon.A
|
||||||
|
|
||||||
if len(conf.Services) == 0 {
|
if len(conf.Services) == 0 {
|
||||||
conf.Services = make(map[string]*dynamic.Service)
|
conf.Services = make(map[string]*dynamic.Service)
|
||||||
lb := &dynamic.LoadBalancerService{}
|
lb := &dynamic.ServersLoadBalancer{}
|
||||||
lb.SetDefaults()
|
lb.SetDefaults()
|
||||||
conf.Services[appName] = &dynamic.Service{
|
conf.Services[appName] = &dynamic.Service{
|
||||||
LoadBalancer: lb,
|
LoadBalancer: lb,
|
||||||
|
|
|
@ -56,7 +56,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {LoadBalancer: &dynamic.LoadBalancerService{
|
"app": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -110,7 +110,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {LoadBalancer: &dynamic.LoadBalancerService{
|
"app": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -156,7 +156,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {LoadBalancer: &dynamic.LoadBalancerService{
|
"app": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -200,7 +200,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {LoadBalancer: &dynamic.LoadBalancerService{
|
"Service1": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:8080",
|
URL: "http://localhost:8080",
|
||||||
|
@ -249,7 +249,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {LoadBalancer: &dynamic.LoadBalancerService{
|
"Service1": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:8080",
|
URL: "http://localhost:8080",
|
||||||
|
@ -300,7 +300,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"foo": {LoadBalancer: &dynamic.LoadBalancerService{
|
"foo": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:8080",
|
URL: "http://localhost:8080",
|
||||||
|
@ -308,7 +308,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
}},
|
}},
|
||||||
"bar": {LoadBalancer: &dynamic.LoadBalancerService{
|
"bar": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:8081",
|
URL: "http://localhost:8081",
|
||||||
|
@ -343,7 +343,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -382,7 +382,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {LoadBalancer: &dynamic.LoadBalancerService{
|
"Service1": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -420,7 +420,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -451,7 +451,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -495,7 +495,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -529,7 +529,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -539,7 +539,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Service2": {
|
"Service2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -629,7 +629,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -639,7 +639,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"app2": {
|
"app2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -686,7 +686,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -696,7 +696,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"app2": {
|
"app2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -734,7 +734,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -744,7 +744,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"app2": {
|
"app2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -789,7 +789,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -830,7 +830,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -840,7 +840,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"app2": {
|
"app2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -877,7 +877,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -915,7 +915,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "h2c://localhost:90",
|
URL: "h2c://localhost:90",
|
||||||
|
@ -948,7 +948,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -958,7 +958,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Service2": {
|
"Service2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:8080",
|
URL: "http://localhost:8080",
|
||||||
|
@ -1123,7 +1123,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -1161,7 +1161,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"app": {
|
"app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -1198,7 +1198,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"a_b_app": {
|
"a_b_app": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
@ -1362,7 +1362,7 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"bar": {
|
"bar": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://localhost:80",
|
URL: "http://localhost:80",
|
||||||
|
|
|
@ -96,7 +96,7 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, service ranche
|
||||||
|
|
||||||
if len(configuration.Services) == 0 {
|
if len(configuration.Services) == 0 {
|
||||||
configuration.Services = make(map[string]*dynamic.Service)
|
configuration.Services = make(map[string]*dynamic.Service)
|
||||||
lb := &dynamic.LoadBalancerService{}
|
lb := &dynamic.ServersLoadBalancer{}
|
||||||
lb.SetDefaults()
|
lb.SetDefaults()
|
||||||
configuration.Services[serviceName] = &dynamic.Service{
|
configuration.Services[serviceName] = &dynamic.Service{
|
||||||
LoadBalancer: lb,
|
LoadBalancer: lb,
|
||||||
|
@ -183,7 +183,7 @@ func (p *Provider) addServerTCP(ctx context.Context, service rancherData, loadBa
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) addServers(ctx context.Context, service rancherData, loadBalancer *dynamic.LoadBalancerService) error {
|
func (p *Provider) addServers(ctx context.Context, service rancherData, loadBalancer *dynamic.ServersLoadBalancer) error {
|
||||||
log.FromContext(ctx).Debugf("Trying to add servers for service %s \n", service.Name)
|
log.FromContext(ctx).Debugf("Trying to add servers for service %s \n", service.Name)
|
||||||
|
|
||||||
serverPort := getLBServerPort(loadBalancer)
|
serverPort := getLBServerPort(loadBalancer)
|
||||||
|
@ -216,7 +216,7 @@ func (p *Provider) addServers(ctx context.Context, service rancherData, loadBala
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLBServerPort(loadBalancer *dynamic.LoadBalancerService) string {
|
func getLBServerPort(loadBalancer *dynamic.ServersLoadBalancer) string {
|
||||||
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
|
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
|
||||||
return loadBalancer.Servers[0].Port
|
return loadBalancer.Servers[0].Port
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -95,7 +95,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test1": {
|
"Test1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -105,7 +105,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Test2": {
|
"Test2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.2:80",
|
URL: "http://127.0.0.2:80",
|
||||||
|
@ -157,7 +157,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test1": {
|
"Test1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -170,7 +170,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Test2": {
|
"Test2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://128.0.0.1:80",
|
URL: "http://128.0.0.1:80",
|
||||||
|
@ -214,7 +214,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -302,7 +302,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -372,7 +372,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -425,7 +425,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -467,7 +467,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Test": {
|
"Test": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
@ -652,7 +652,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Middlewares: map[string]*dynamic.Middleware{},
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"Service1": {
|
"Service1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
|
|
@ -48,7 +48,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -85,7 +85,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -108,7 +108,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -132,7 +132,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -173,7 +173,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -213,7 +213,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service@provider-1": {
|
"foo-service@provider-1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -236,7 +236,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service@provider-2": {
|
"foo-service@provider-2": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -260,7 +260,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service@provider-1": {
|
"foo-service@provider-1": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -355,7 +355,7 @@ func TestAccessLog(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -383,7 +383,7 @@ func TestAccessLog(t *testing.T) {
|
||||||
},
|
},
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -448,7 +448,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
desc: "No error",
|
desc: "No error",
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1:8085",
|
URL: "http://127.0.0.1:8085",
|
||||||
|
@ -482,7 +482,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
desc: "One router with wrong rule",
|
desc: "One router with wrong rule",
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -509,7 +509,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
desc: "All router with wrong rule",
|
desc: "All router with wrong rule",
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -536,7 +536,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
desc: "Router with unknown service",
|
desc: "Router with unknown service",
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -579,7 +579,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
desc: "Router with middleware",
|
desc: "Router with middleware",
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -619,7 +619,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
desc: "Router with unknown middleware",
|
desc: "Router with unknown middleware",
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -650,7 +650,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
desc: "Router with broken middleware",
|
desc: "Router with broken middleware",
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
serviceConfig: map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://127.0.0.1",
|
URL: "http://127.0.0.1",
|
||||||
|
@ -749,7 +749,7 @@ func BenchmarkRouterServe(b *testing.B) {
|
||||||
}
|
}
|
||||||
serviceConfig := map[string]*dynamic.Service{
|
serviceConfig := map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server.URL,
|
URL: server.URL,
|
||||||
|
@ -793,7 +793,7 @@ func BenchmarkService(b *testing.B) {
|
||||||
|
|
||||||
serviceConfig := map[string]*dynamic.Service{
|
serviceConfig := map[string]*dynamic.Service{
|
||||||
"foo-service": {
|
"foo-service": {
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "tchouck",
|
URL: "tchouck",
|
||||||
|
|
|
@ -199,7 +199,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
th.WithRule(routeRule)),
|
th.WithRule(routeRule)),
|
||||||
),
|
),
|
||||||
th.WithLoadBalancerServices(th.WithService("bar",
|
th.WithLoadBalancerServices(th.WithService("bar",
|
||||||
th.WithStickiness("test")),
|
th.WithSticky("test")),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -229,7 +229,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
th.WithRule(routeRule)),
|
th.WithRule(routeRule)),
|
||||||
),
|
),
|
||||||
th.WithLoadBalancerServices(th.WithService("bar",
|
th.WithLoadBalancerServices(th.WithService("bar",
|
||||||
th.WithStickiness("test")),
|
th.WithSticky("test")),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
155
pkg/server/service/loadbalancer/wrr/wrr.go
Normal file
155
pkg/server/service/loadbalancer/wrr/wrr.go
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
package wrr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type namedHandler struct {
|
||||||
|
http.Handler
|
||||||
|
name string
|
||||||
|
weight int
|
||||||
|
}
|
||||||
|
|
||||||
|
type stickyCookie struct {
|
||||||
|
name string
|
||||||
|
secure bool
|
||||||
|
httpOnly bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new load balancer.
|
||||||
|
func New(sticky *dynamic.Sticky) *Balancer {
|
||||||
|
balancer := &Balancer{
|
||||||
|
mutex: &sync.Mutex{},
|
||||||
|
index: -1,
|
||||||
|
}
|
||||||
|
if sticky != nil && sticky.Cookie != nil {
|
||||||
|
balancer.stickyCookie = &stickyCookie{
|
||||||
|
name: sticky.Cookie.Name,
|
||||||
|
secure: sticky.Cookie.Secure,
|
||||||
|
httpOnly: sticky.Cookie.HTTPOnly,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return balancer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Balancer is a WeightedRoundRobin load balancer.
|
||||||
|
type Balancer struct {
|
||||||
|
handlers []*namedHandler
|
||||||
|
mutex *sync.Mutex
|
||||||
|
// Current index (starts from -1)
|
||||||
|
index int
|
||||||
|
currentWeight int
|
||||||
|
stickyCookie *stickyCookie
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Balancer) maxWeight() int {
|
||||||
|
max := -1
|
||||||
|
for _, s := range b.handlers {
|
||||||
|
if s.weight > max {
|
||||||
|
max = s.weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Balancer) weightGcd() int {
|
||||||
|
divisor := -1
|
||||||
|
for _, s := range b.handlers {
|
||||||
|
if divisor == -1 {
|
||||||
|
divisor = s.weight
|
||||||
|
} else {
|
||||||
|
divisor = gcd(divisor, s.weight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return divisor
|
||||||
|
}
|
||||||
|
|
||||||
|
func gcd(a, b int) int {
|
||||||
|
for b != 0 {
|
||||||
|
a, b = b, a%b
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Balancer) nextServer() (*namedHandler, error) {
|
||||||
|
b.mutex.Lock()
|
||||||
|
defer b.mutex.Unlock()
|
||||||
|
|
||||||
|
if len(b.handlers) == 0 {
|
||||||
|
return nil, fmt.Errorf("no servers in the pool")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The algo below may look messy, but is actually very simple
|
||||||
|
// it calculates the GCD and subtracts it on every iteration, what interleaves servers
|
||||||
|
// and allows us not to build an iterator every time we readjust weights
|
||||||
|
|
||||||
|
// GCD across all enabled servers
|
||||||
|
gcd := b.weightGcd()
|
||||||
|
// Maximum weight across all enabled servers
|
||||||
|
max := b.maxWeight()
|
||||||
|
|
||||||
|
for {
|
||||||
|
b.index = (b.index + 1) % len(b.handlers)
|
||||||
|
if b.index == 0 {
|
||||||
|
b.currentWeight -= gcd
|
||||||
|
if b.currentWeight <= 0 {
|
||||||
|
b.currentWeight = max
|
||||||
|
if b.currentWeight == 0 {
|
||||||
|
return nil, fmt.Errorf("all servers have 0 weight")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srv := b.handlers[b.index]
|
||||||
|
if srv.weight >= b.currentWeight {
|
||||||
|
log.WithoutContext().Debugf("Service Select: %s", srv.name)
|
||||||
|
return srv, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Balancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if b.stickyCookie != nil {
|
||||||
|
cookie, err := req.Cookie(b.stickyCookie.name)
|
||||||
|
|
||||||
|
if err != nil && err != http.ErrNoCookie {
|
||||||
|
log.WithoutContext().Warnf("Error while reading cookie: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && cookie != nil {
|
||||||
|
for _, handler := range b.handlers {
|
||||||
|
if handler.name == cookie.Value {
|
||||||
|
handler.ServeHTTP(w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := b.nextServer()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, http.StatusText(http.StatusInternalServerError)+err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.stickyCookie != nil {
|
||||||
|
cookie := &http.Cookie{Name: b.stickyCookie.name, Value: server.name, Path: "/", HttpOnly: b.stickyCookie.httpOnly, Secure: b.stickyCookie.secure}
|
||||||
|
http.SetCookie(w, cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
server.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddService adds a handler.
|
||||||
|
// It is not thread safe with ServeHTTP.
|
||||||
|
func (b *Balancer) AddService(name string, handler http.Handler, weight *int) {
|
||||||
|
w := 1
|
||||||
|
if weight != nil {
|
||||||
|
w = *weight
|
||||||
|
}
|
||||||
|
b.handlers = append(b.handlers, &namedHandler{Handler: handler, name: name, weight: w})
|
||||||
|
}
|
115
pkg/server/service/loadbalancer/wrr/wrr_test.go
Normal file
115
pkg/server/service/loadbalancer/wrr/wrr_test.go
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
package wrr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Int(v int) *int { return &v }
|
||||||
|
|
||||||
|
type responseRecorder struct {
|
||||||
|
*httptest.ResponseRecorder
|
||||||
|
save map[string]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *responseRecorder) WriteHeader(statusCode int) {
|
||||||
|
r.save[r.Header().Get("server")]++
|
||||||
|
r.ResponseRecorder.WriteHeader(statusCode)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBalancer(t *testing.T) {
|
||||||
|
balancer := New(nil)
|
||||||
|
|
||||||
|
balancer.AddService("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.Header().Set("server", "first")
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
}), Int(3))
|
||||||
|
|
||||||
|
balancer.AddService("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.Header().Set("server", "second")
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
}), Int(1))
|
||||||
|
|
||||||
|
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 3, recorder.save["first"])
|
||||||
|
assert.Equal(t, 1, recorder.save["second"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBalancerNoService(t *testing.T) {
|
||||||
|
balancer := New(nil)
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusInternalServerError, recorder.Result().StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBalancerOneServerZeroWeight(t *testing.T) {
|
||||||
|
balancer := New(nil)
|
||||||
|
|
||||||
|
balancer.AddService("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.Header().Set("server", "first")
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
}), Int(1))
|
||||||
|
|
||||||
|
balancer.AddService("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
|
||||||
|
|
||||||
|
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 3, recorder.save["first"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBalancerAllServersZeroWeight(t *testing.T) {
|
||||||
|
balancer := New(nil)
|
||||||
|
|
||||||
|
balancer.AddService("test", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
|
||||||
|
balancer.AddService("test2", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusInternalServerError, recorder.Result().StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSticky(t *testing.T) {
|
||||||
|
balancer := New(&dynamic.Sticky{
|
||||||
|
Cookie: &dynamic.Cookie{Name: "test"},
|
||||||
|
})
|
||||||
|
|
||||||
|
balancer.AddService("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.Header().Set("server", "first")
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
}), Int(1))
|
||||||
|
|
||||||
|
balancer.AddService("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.Header().Set("server", "second")
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
}), Int(2))
|
||||||
|
|
||||||
|
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
for _, cookie := range recorder.Result().Cookies() {
|
||||||
|
req.AddCookie(cookie)
|
||||||
|
}
|
||||||
|
recorder.ResponseRecorder = httptest.NewRecorder()
|
||||||
|
|
||||||
|
balancer.ServeHTTP(recorder, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 0, recorder.save["first"])
|
||||||
|
assert.Equal(t, 3, recorder.save["second"])
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
@ -20,6 +21,7 @@ import (
|
||||||
"github.com/containous/traefik/v2/pkg/middlewares/pipelining"
|
"github.com/containous/traefik/v2/pkg/middlewares/pipelining"
|
||||||
"github.com/containous/traefik/v2/pkg/server/cookie"
|
"github.com/containous/traefik/v2/pkg/server/cookie"
|
||||||
"github.com/containous/traefik/v2/pkg/server/internal"
|
"github.com/containous/traefik/v2/pkg/server/internal"
|
||||||
|
"github.com/containous/traefik/v2/pkg/server/service/loadbalancer/wrr"
|
||||||
"github.com/vulcand/oxy/roundrobin"
|
"github.com/vulcand/oxy/roundrobin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,27 +62,58 @@ func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string, respons
|
||||||
return nil, fmt.Errorf("the service %q does not exist", serviceName)
|
return nil, fmt.Errorf("the service %q does not exist", serviceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Should handle multiple service types
|
if conf.LoadBalancer != nil && conf.Weighted != nil {
|
||||||
// FIXME Check if the service is declared multiple times with different types
|
return nil, errors.New("cannot create service: multi-types service not supported, consider declaring two different pieces of service instead")
|
||||||
if conf.LoadBalancer == nil {
|
|
||||||
sErr := fmt.Errorf("the service %q doesn't have any load balancer", serviceName)
|
|
||||||
conf.AddError(sErr, true)
|
|
||||||
return nil, sErr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lb, err := m.getLoadBalancerServiceHandler(ctx, serviceName, conf.LoadBalancer, responseModifier)
|
var lb http.Handler
|
||||||
if err != nil {
|
|
||||||
conf.AddError(err, true)
|
switch {
|
||||||
return nil, err
|
case conf.LoadBalancer != nil:
|
||||||
|
var err error
|
||||||
|
lb, err = m.getLoadBalancerServiceHandler(ctx, serviceName, conf.LoadBalancer, responseModifier)
|
||||||
|
if err != nil {
|
||||||
|
conf.AddError(err, true)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case conf.Weighted != nil:
|
||||||
|
var err error
|
||||||
|
lb, err = m.getLoadBalancerWRRServiceHandler(ctx, serviceName, conf.Weighted, responseModifier)
|
||||||
|
if err != nil {
|
||||||
|
conf.AddError(err, true)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
sErr := fmt.Errorf("the service %q does not have any type defined", serviceName)
|
||||||
|
conf.AddError(sErr, true)
|
||||||
|
return nil, sErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return lb, nil
|
return lb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) getLoadBalancerWRRServiceHandler(ctx context.Context, serviceName string, config *dynamic.WeightedRoundRobin, responseModifier func(*http.Response) error) (http.Handler, error) {
|
||||||
|
// TODO Handle accesslog and metrics with multiple service name
|
||||||
|
if config.Sticky != nil && config.Sticky.Cookie != nil {
|
||||||
|
config.Sticky.Cookie.Name = cookie.GetName(config.Sticky.Cookie.Name, serviceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
balancer := wrr.New(config.Sticky)
|
||||||
|
for _, service := range config.Services {
|
||||||
|
serviceHandler, err := m.BuildHTTP(ctx, service.Name, responseModifier)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
balancer.AddService(service.Name, serviceHandler, service.Weight)
|
||||||
|
}
|
||||||
|
return balancer, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) getLoadBalancerServiceHandler(
|
func (m *Manager) getLoadBalancerServiceHandler(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
serviceName string,
|
serviceName string,
|
||||||
service *dynamic.LoadBalancerService,
|
service *dynamic.ServersLoadBalancer,
|
||||||
responseModifier func(*http.Response) error,
|
responseModifier func(*http.Response) error,
|
||||||
) (http.Handler, error) {
|
) (http.Handler, error) {
|
||||||
fwd, err := buildProxy(service.PassHostHeader, service.ResponseForwarding, m.defaultRoundTripper, m.bufferPool, responseModifier)
|
fwd, err := buildProxy(service.PassHostHeader, service.ResponseForwarding, m.defaultRoundTripper, m.bufferPool, responseModifier)
|
||||||
|
@ -193,16 +226,16 @@ func buildHealthCheckOptions(ctx context.Context, lb healthcheck.BalancerHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, service *dynamic.LoadBalancerService, fwd http.Handler) (healthcheck.BalancerHandler, error) {
|
func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, service *dynamic.ServersLoadBalancer, fwd http.Handler) (healthcheck.BalancerHandler, error) {
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
logger.Debug("Creating load-balancer")
|
logger.Debug("Creating load-balancer")
|
||||||
|
|
||||||
var options []roundrobin.LBOption
|
var options []roundrobin.LBOption
|
||||||
|
|
||||||
var cookieName string
|
var cookieName string
|
||||||
if stickiness := service.Stickiness; stickiness != nil {
|
if service.Sticky != nil && service.Sticky.Cookie != nil {
|
||||||
cookieName = cookie.GetName(stickiness.CookieName, serviceName)
|
cookieName = cookie.GetName(service.Sticky.Cookie.Name, serviceName)
|
||||||
opts := roundrobin.CookieOptions{HTTPOnly: stickiness.HTTPOnlyCookie, Secure: stickiness.SecureCookie}
|
opts := roundrobin.CookieOptions{HTTPOnly: service.Sticky.Cookie.HTTPOnly, Secure: service.Sticky.Cookie.Secure}
|
||||||
options = append(options, roundrobin.EnableStickySession(roundrobin.NewStickySessionWithOptions(cookieName, opts)))
|
options = append(options, roundrobin.EnableStickySession(roundrobin.NewStickySessionWithOptions(cookieName, opts)))
|
||||||
logger.Debugf("Sticky session cookie name: %v", cookieName)
|
logger.Debugf("Sticky session cookie name: %v", cookieName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,14 +27,14 @@ func TestGetLoadBalancer(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
serviceName string
|
serviceName string
|
||||||
service *dynamic.LoadBalancerService
|
service *dynamic.ServersLoadBalancer
|
||||||
fwd http.Handler
|
fwd http.Handler
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Fails when provided an invalid URL",
|
desc: "Fails when provided an invalid URL",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: ":",
|
URL: ":",
|
||||||
|
@ -47,15 +47,15 @@ func TestGetLoadBalancer(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "Succeeds when there are no servers",
|
desc: "Succeeds when there are no servers",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{},
|
service: &dynamic.ServersLoadBalancer{},
|
||||||
fwd: &MockForwarder{},
|
fwd: &MockForwarder{},
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Succeeds when stickiness is set",
|
desc: "Succeeds when sticky.cookie is set",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Stickiness: &dynamic.Stickiness{},
|
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||||
},
|
},
|
||||||
fwd: &MockForwarder{},
|
fwd: &MockForwarder{},
|
||||||
expectError: false,
|
expectError: false,
|
||||||
|
@ -114,7 +114,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
serviceName string
|
serviceName string
|
||||||
service *dynamic.LoadBalancerService
|
service *dynamic.ServersLoadBalancer
|
||||||
responseModifier func(*http.Response) error
|
responseModifier func(*http.Response) error
|
||||||
|
|
||||||
expected []ExpectedResult
|
expected []ExpectedResult
|
||||||
|
@ -122,7 +122,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "Load balances between the two servers",
|
desc: "Load balances between the two servers",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server1.URL,
|
URL: server1.URL,
|
||||||
|
@ -146,7 +146,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "StatusBadGateway when the server is not reachable",
|
desc: "StatusBadGateway when the server is not reachable",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: "http://foo",
|
URL: "http://foo",
|
||||||
|
@ -162,7 +162,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "ServiceUnavailable when no servers are available",
|
desc: "ServiceUnavailable when no servers are available",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Servers: []dynamic.Server{},
|
Servers: []dynamic.Server{},
|
||||||
},
|
},
|
||||||
expected: []ExpectedResult{
|
expected: []ExpectedResult{
|
||||||
|
@ -172,10 +172,10 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Always call the same server when stickiness is true",
|
desc: "Always call the same server when sticky.cookie is true",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Stickiness: &dynamic.Stickiness{},
|
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server1.URL,
|
URL: server1.URL,
|
||||||
|
@ -199,8 +199,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "Sticky Cookie's options set correctly",
|
desc: "Sticky Cookie's options set correctly",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Stickiness: &dynamic.Stickiness{HTTPOnlyCookie: true, SecureCookie: true},
|
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{HTTPOnly: true, Secure: true}},
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: server1.URL,
|
URL: server1.URL,
|
||||||
|
@ -219,8 +219,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "PassHost passes the host instead of the IP",
|
desc: "PassHost passes the host instead of the IP",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Stickiness: &dynamic.Stickiness{},
|
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
|
@ -238,8 +238,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "PassHost doesn't passe the host instead of the IP",
|
desc: "PassHost doesn't passe the host instead of the IP",
|
||||||
serviceName: "test",
|
serviceName: "test",
|
||||||
service: &dynamic.LoadBalancerService{
|
service: &dynamic.ServersLoadBalancer{
|
||||||
Stickiness: &dynamic.Stickiness{},
|
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||||
Servers: []dynamic.Server{
|
Servers: []dynamic.Server{
|
||||||
{
|
{
|
||||||
URL: serverPassHostFalse.URL,
|
URL: serverPassHostFalse.URL,
|
||||||
|
@ -297,7 +297,7 @@ func TestManager_Build(t *testing.T) {
|
||||||
configs: map[string]*runtime.ServiceInfo{
|
configs: map[string]*runtime.ServiceInfo{
|
||||||
"serviceName": {
|
"serviceName": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{},
|
LoadBalancer: &dynamic.ServersLoadBalancer{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -308,7 +308,7 @@ func TestManager_Build(t *testing.T) {
|
||||||
configs: map[string]*runtime.ServiceInfo{
|
configs: map[string]*runtime.ServiceInfo{
|
||||||
"serviceName@provider-1": {
|
"serviceName@provider-1": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{},
|
LoadBalancer: &dynamic.ServersLoadBalancer{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -319,7 +319,7 @@ func TestManager_Build(t *testing.T) {
|
||||||
configs: map[string]*runtime.ServiceInfo{
|
configs: map[string]*runtime.ServiceInfo{
|
||||||
"serviceName@provider-1": {
|
"serviceName@provider-1": {
|
||||||
Service: &dynamic.Service{
|
Service: &dynamic.Service{
|
||||||
LoadBalancer: &dynamic.LoadBalancerService{},
|
LoadBalancer: &dynamic.ServersLoadBalancer{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,11 +50,11 @@ func WithServiceName(serviceName string) func(*dynamic.Router) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithLoadBalancerServices is a helper to create a configuration.
|
// WithLoadBalancerServices is a helper to create a configuration.
|
||||||
func WithLoadBalancerServices(opts ...func(service *dynamic.LoadBalancerService) string) func(*dynamic.HTTPConfiguration) {
|
func WithLoadBalancerServices(opts ...func(service *dynamic.ServersLoadBalancer) string) func(*dynamic.HTTPConfiguration) {
|
||||||
return func(c *dynamic.HTTPConfiguration) {
|
return func(c *dynamic.HTTPConfiguration) {
|
||||||
c.Services = make(map[string]*dynamic.Service)
|
c.Services = make(map[string]*dynamic.Service)
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
b := &dynamic.LoadBalancerService{}
|
b := &dynamic.ServersLoadBalancer{}
|
||||||
name := opt(b)
|
name := opt(b)
|
||||||
c.Services[name] = &dynamic.Service{
|
c.Services[name] = &dynamic.Service{
|
||||||
LoadBalancer: b,
|
LoadBalancer: b,
|
||||||
|
@ -64,8 +64,8 @@ func WithLoadBalancerServices(opts ...func(service *dynamic.LoadBalancerService)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithService is a helper to create a configuration.
|
// WithService is a helper to create a configuration.
|
||||||
func WithService(name string, opts ...func(*dynamic.LoadBalancerService)) func(*dynamic.LoadBalancerService) string {
|
func WithService(name string, opts ...func(*dynamic.ServersLoadBalancer)) func(*dynamic.ServersLoadBalancer) string {
|
||||||
return func(r *dynamic.LoadBalancerService) string {
|
return func(r *dynamic.ServersLoadBalancer) string {
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(r)
|
opt(r)
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,8 @@ func WithRule(rule string) func(*dynamic.Router) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithServers is a helper to create a configuration.
|
// WithServers is a helper to create a configuration.
|
||||||
func WithServers(opts ...func(*dynamic.Server)) func(*dynamic.LoadBalancerService) {
|
func WithServers(opts ...func(*dynamic.Server)) func(*dynamic.ServersLoadBalancer) {
|
||||||
return func(b *dynamic.LoadBalancerService) {
|
return func(b *dynamic.ServersLoadBalancer) {
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
server := dynamic.Server{}
|
server := dynamic.Server{}
|
||||||
opt(&server)
|
opt(&server)
|
||||||
|
@ -137,11 +137,11 @@ func WithServer(url string, opts ...func(*dynamic.Server)) func(*dynamic.Server)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithStickiness is a helper to create a configuration.
|
// WithSticky is a helper to create a configuration.
|
||||||
func WithStickiness(cookieName string) func(*dynamic.LoadBalancerService) {
|
func WithSticky(cookieName string) func(*dynamic.ServersLoadBalancer) {
|
||||||
return func(b *dynamic.LoadBalancerService) {
|
return func(b *dynamic.ServersLoadBalancer) {
|
||||||
b.Stickiness = &dynamic.Stickiness{
|
b.Sticky = &dynamic.Sticky{
|
||||||
CookieName: cookieName,
|
Cookie: &dynamic.Cookie{Name: cookieName},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue