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
|
||||
# only support "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
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
# (default 1) A weight used by the weighted round-robin strategy (WRR).
|
||||
weight: 1
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
|
|
|
@ -130,10 +130,10 @@
|
|||
- "traefik.http.services.service0.loadbalancer.healthcheck.timeout=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.passhostheader=true"
|
||||
- "traefik.http.services.service0.loadbalancer.responseforwarding.flushinterval=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.stickiness=true"
|
||||
- "traefik.http.services.service0.loadbalancer.stickiness.cookiename=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.stickiness.httponlycookie=true"
|
||||
- "traefik.http.services.service0.loadbalancer.stickiness.securecookie=true"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky=true"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky.cookie.name=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky.cookie.httponly=true"
|
||||
- "traefik.http.services.service0.loadbalancer.sticky.cookie.secure=true"
|
||||
- "traefik.http.services.service0.loadbalancer.server.port=foobar"
|
||||
- "traefik.http.services.service0.loadbalancer.server.scheme=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.passhostheader=true"
|
||||
- "traefik.http.services.service1.loadbalancer.responseforwarding.flushinterval=foobar"
|
||||
- "traefik.http.services.service1.loadbalancer.stickiness=true"
|
||||
- "traefik.http.services.service1.loadbalancer.stickiness.cookiename=foobar"
|
||||
- "traefik.http.services.service1.loadbalancer.stickiness.httponlycookie=true"
|
||||
- "traefik.http.services.service1.loadbalancer.stickiness.securecookie=true"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky=true"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky.cookie.name=foobar"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky.cookie.httponly=true"
|
||||
- "traefik.http.services.service1.loadbalancer.sticky.cookie.secure=true"
|
||||
- "traefik.http.services.service1.loadbalancer.server.port=foobar"
|
||||
- "traefik.http.services.service1.loadbalancer.server.scheme=foobar"
|
||||
- "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar"
|
||||
|
|
|
@ -35,56 +35,47 @@
|
|||
main = "foobar"
|
||||
sans = ["foobar", "foobar"]
|
||||
[http.services]
|
||||
[http.services.Service0]
|
||||
[http.services.Service0.loadBalancer]
|
||||
[http.services.Service01]
|
||||
[http.services.Service01.loadBalancer]
|
||||
passHostHeader = true
|
||||
[http.services.Service0.loadBalancer.stickiness]
|
||||
cookieName = "foobar"
|
||||
secureCookie = true
|
||||
httpOnlyCookie = true
|
||||
[http.services.Service01.loadBalancer.sticky]
|
||||
[http.services.Service01.loadBalancer.sticky.cookie]
|
||||
name = "foobar"
|
||||
secure = true
|
||||
httpOnly = true
|
||||
|
||||
[[http.services.Service0.loadBalancer.servers]]
|
||||
[[http.services.Service01.loadBalancer.servers]]
|
||||
url = "foobar"
|
||||
|
||||
[[http.services.Service0.loadBalancer.servers]]
|
||||
[[http.services.Service01.loadBalancer.servers]]
|
||||
url = "foobar"
|
||||
[http.services.Service0.loadBalancer.healthCheck]
|
||||
[http.services.Service01.loadBalancer.healthCheck]
|
||||
scheme = "foobar"
|
||||
path = "foobar"
|
||||
port = 42
|
||||
interval = "foobar"
|
||||
timeout = "foobar"
|
||||
hostname = "foobar"
|
||||
[http.services.Service0.loadBalancer.healthCheck.headers]
|
||||
[http.services.Service01.loadBalancer.healthCheck.headers]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[http.services.Service0.loadBalancer.responseForwarding]
|
||||
[http.services.Service01.loadBalancer.responseForwarding]
|
||||
flushInterval = "foobar"
|
||||
[http.services.Service1]
|
||||
[http.services.Service1.loadBalancer]
|
||||
passHostHeader = true
|
||||
[http.services.Service1.loadBalancer.stickiness]
|
||||
cookieName = "foobar"
|
||||
secureCookie = true
|
||||
httpOnlyCookie = true
|
||||
[http.services.Service02]
|
||||
[http.services.Service02.weighted]
|
||||
|
||||
[[http.services.Service1.loadBalancer.servers]]
|
||||
url = "foobar"
|
||||
[[http.services.Service02.weighted.services]]
|
||||
name = "foobar"
|
||||
weight = 42
|
||||
|
||||
[[http.services.Service1.loadBalancer.servers]]
|
||||
url = "foobar"
|
||||
[http.services.Service1.loadBalancer.healthCheck]
|
||||
scheme = "foobar"
|
||||
path = "foobar"
|
||||
port = 42
|
||||
interval = "foobar"
|
||||
timeout = "foobar"
|
||||
hostname = "foobar"
|
||||
[http.services.Service1.loadBalancer.healthCheck.headers]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[http.services.Service1.loadBalancer.responseForwarding]
|
||||
flushInterval = "foobar"
|
||||
[[http.services.Service02.weighted.services]]
|
||||
name = "foobar"
|
||||
weight = 42
|
||||
[http.services.Service02.weighted.sticky]
|
||||
[http.services.Service02.weighted.sticky.cookie]
|
||||
name = "foobar"
|
||||
secure = true
|
||||
httpOnly = true
|
||||
[http.middlewares]
|
||||
[http.middlewares.Middleware00]
|
||||
[http.middlewares.Middleware00.addPrefix]
|
||||
|
|
|
@ -45,34 +45,13 @@ http:
|
|||
- foobar
|
||||
- foobar
|
||||
services:
|
||||
Service0:
|
||||
Service01:
|
||||
loadBalancer:
|
||||
stickiness:
|
||||
cookieName: foobar
|
||||
secureCookie: true
|
||||
httpOnlyCookie: true
|
||||
servers:
|
||||
- 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
|
||||
sticky:
|
||||
cookie:
|
||||
name: foobar
|
||||
secure: true
|
||||
httpOnly: true
|
||||
servers:
|
||||
- url: foobar
|
||||
- url: foobar
|
||||
|
@ -89,6 +68,18 @@ http:
|
|||
passHostHeader: true
|
||||
responseForwarding:
|
||||
flushInterval: foobar
|
||||
Service02:
|
||||
weighted:
|
||||
services:
|
||||
- name: foobar
|
||||
weight: 42
|
||||
- name: foobar
|
||||
weight: 42
|
||||
sticky:
|
||||
cookie:
|
||||
name: foobar
|
||||
secure: true
|
||||
httpOnly: true
|
||||
middlewares:
|
||||
Middleware00:
|
||||
addPrefix:
|
||||
|
|
|
@ -130,10 +130,10 @@
|
|||
"traefik.http.services.service0.loadbalancer.healthcheck.timeout": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.passhostheader": "true",
|
||||
"traefik.http.services.service0.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.stickiness": "true",
|
||||
"traefik.http.services.service0.loadbalancer.stickiness.cookiename": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.stickiness.httponlycookie": "true",
|
||||
"traefik.http.services.service0.loadbalancer.stickiness.securecookie": "true",
|
||||
"traefik.http.services.service0.loadbalancer.sticky": "true",
|
||||
"traefik.http.services.service0.loadbalancer.sticky.cookie.name": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.sticky.cookie.httponly": "true",
|
||||
"traefik.http.services.service0.loadbalancer.sticky.cookie.secure": "true",
|
||||
"traefik.http.services.service0.loadbalancer.server.port": "foobar",
|
||||
"traefik.http.services.service0.loadbalancer.server.scheme": "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.passhostheader": "true",
|
||||
"traefik.http.services.service1.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||
"traefik.http.services.service1.loadbalancer.stickiness": "true",
|
||||
"traefik.http.services.service1.loadbalancer.stickiness.cookiename": "foobar",
|
||||
"traefik.http.services.service1.loadbalancer.stickiness.httponlycookie": "true",
|
||||
"traefik.http.services.service1.loadbalancer.stickiness.securecookie": "true",
|
||||
"traefik.http.services.service1.loadbalancer.sticky": "true",
|
||||
"traefik.http.services.service1.loadbalancer.sticky.cookie.name": "foobar",
|
||||
"traefik.http.services.service1.loadbalancer.sticky.cookie.secure": "true",
|
||||
"traefik.http.services.service1.loadbalancer.sticky.cookie.httponly": "true",
|
||||
"traefik.http.services.service1.loadbalancer.server.port": "foobar",
|
||||
"traefik.http.services.service1.loadbalancer.server.scheme": "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
|
||||
|
||||
### General
|
||||
|
||||
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
|
||||
### Servers Load Balancer
|
||||
|
||||
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"
|
||||
[http.services]
|
||||
[http.services.my-service]
|
||||
[http.services.my-service.loadBalancer.stickiness]
|
||||
[http.services.my-service.loadBalancer.sticky.cookie]
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
|
@ -169,18 +163,19 @@ On subsequent requests, the client is forwarded to the same server.
|
|||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
stickiness: {}
|
||||
sticky:
|
||||
cookie: {}
|
||||
```
|
||||
|
||||
??? example "Adding Stickiness with a Custom Cookie Name"
|
||||
??? example "Adding Stickiness with custom Options"
|
||||
|
||||
```toml tab="TOML"
|
||||
[http.services]
|
||||
[http.services.my-service]
|
||||
[http.services.my-service.loadBalancer.stickiness]
|
||||
cookieName = "my_stickiness_cookie_name"
|
||||
secureCookie = true
|
||||
httpOnlyCookie = true
|
||||
[http.services.my-service.loadBalancer.sticky.cookie]
|
||||
name = "my_sticky_cookie_name"
|
||||
secure = true
|
||||
httpOnly = true
|
||||
```
|
||||
|
||||
```yaml tab="YAML"
|
||||
|
@ -188,10 +183,11 @@ On subsequent requests, the client is forwarded to the same server.
|
|||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
stickiness:
|
||||
cookieName: my_stickiness_cookie_name
|
||||
secureCookie: true
|
||||
httpOnlyCookie: true
|
||||
sticky:
|
||||
cookie:
|
||||
name: my_sticky_cookie_name
|
||||
secure: true
|
||||
httpOnly: true
|
||||
```
|
||||
|
||||
#### Health Check
|
||||
|
@ -306,6 +302,57 @@ Below are the available options for the health check mechanism:
|
|||
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
|
||||
|
||||
### General
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
[tcp.services.whoami-no-cert]
|
||||
[tcp.services.whoami-no-cert.loadBalancer]
|
||||
method = "wrr"
|
||||
[[tcp.services.whoami-no-cert.loadBalancer.servers]]
|
||||
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{
|
||||
"service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
|
@ -563,7 +564,7 @@ func (s *SimpleSuite) TestServiceConfigErrors(c *check.C) {
|
|||
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(`["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)
|
||||
|
||||
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"`))
|
||||
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 {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -219,7 +219,7 @@ func TestHandler_HTTP(t *testing.T) {
|
|||
"baz@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2",
|
||||
|
@ -248,7 +248,7 @@ func TestHandler_HTTP(t *testing.T) {
|
|||
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -264,7 +264,7 @@ func TestHandler_HTTP(t *testing.T) {
|
|||
"baz@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2",
|
||||
|
@ -280,7 +280,7 @@ func TestHandler_HTTP(t *testing.T) {
|
|||
"test@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.3",
|
||||
|
@ -309,7 +309,7 @@ func TestHandler_HTTP(t *testing.T) {
|
|||
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -337,7 +337,7 @@ func TestHandler_HTTP(t *testing.T) {
|
|||
"bar@myprovider": func() *runtime.ServiceInfo {
|
||||
si := &runtime.ServiceInfo{
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
|
|
@ -55,7 +55,7 @@ func TestHandler_Overview(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
||||
},
|
||||
},
|
||||
|
@ -63,7 +63,7 @@ func TestHandler_Overview(t *testing.T) {
|
|||
},
|
||||
"bar-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
||||
},
|
||||
},
|
||||
|
@ -71,7 +71,7 @@ func TestHandler_Overview(t *testing.T) {
|
|||
},
|
||||
"fii-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{{URL: "http://127.0.0.1"}},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -37,7 +37,7 @@ func TestHandler_RawData(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
|
|
@ -404,8 +404,8 @@
|
|||
[http.services.Service0]
|
||||
[http.services.Service0.loadBalancer]
|
||||
passHostHeader = true
|
||||
[http.services.Service0.loadBalancer.stickiness]
|
||||
cookieName = "foobar"
|
||||
[http.services.Service0.loadBalancer.sticky.cookie]
|
||||
name = "foobar"
|
||||
|
||||
[[http.services.Service0.loadBalancer.servers]]
|
||||
url = "foobar"
|
||||
|
|
|
@ -19,7 +19,8 @@ type HTTPConfiguration struct {
|
|||
|
||||
// Service holds a service configuration (can only be of one type at the same time).
|
||||
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
|
||||
|
@ -45,9 +46,47 @@ type RouterTLSConfig struct {
|
|||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// LoadBalancerService holds the LoadBalancerService configuration.
|
||||
type LoadBalancerService struct {
|
||||
Stickiness *Stickiness `json:"stickiness,omitempty" toml:"stickiness,omitempty" yaml:"stickiness,omitempty" label:"allowEmpty"`
|
||||
// WeightedRoundRobin is a weighted round robin load-balancer of services.
|
||||
type WeightedRoundRobin struct {
|
||||
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"`
|
||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty"`
|
||||
PassHostHeader bool `json:"passHostHeader" toml:"passHostHeader" yaml:"passHostHeader"`
|
||||
|
@ -55,7 +94,7 @@ type LoadBalancerService struct {
|
|||
}
|
||||
|
||||
// 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
|
||||
defer func() {
|
||||
l.Servers = savedServers
|
||||
|
@ -71,8 +110,8 @@ func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool
|
|||
return reflect.DeepEqual(l, loadBalancer)
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a LoadBalancerService.
|
||||
func (l *LoadBalancerService) SetDefaults() {
|
||||
// SetDefaults Default values for a ServersLoadBalancer.
|
||||
func (l *ServersLoadBalancer) SetDefaults() {
|
||||
l.PassHostHeader = true
|
||||
}
|
||||
|
||||
|
@ -85,15 +124,6 @@ type ResponseForwarding struct {
|
|||
|
||||
// +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.
|
||||
type Server struct {
|
||||
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"`
|
||||
|
|
|
@ -45,7 +45,7 @@ type RouterTCPTLSConfig struct {
|
|||
|
||||
// TCPLoadBalancerService holds the LoadBalancerService configuration.
|
||||
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.
|
||||
|
|
|
@ -247,6 +247,22 @@ func (in Configurations) DeepCopy() Configurations {
|
|||
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.
|
||||
func (in *DigestAuth) DeepCopyInto(out *DigestAuth) {
|
||||
*out = *in
|
||||
|
@ -508,42 +524,6 @@ func (in *IPWhiteList) DeepCopy() *IPWhiteList {
|
|||
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.
|
||||
func (in *MaxConn) DeepCopyInto(out *MaxConn) {
|
||||
*out = *in
|
||||
|
@ -954,12 +934,53 @@ func (in *Server) DeepCopy() *Server {
|
|||
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.
|
||||
func (in *Service) DeepCopyInto(out *Service) {
|
||||
*out = *in
|
||||
if in.LoadBalancer != nil {
|
||||
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)
|
||||
}
|
||||
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.
|
||||
func (in *Stickiness) DeepCopyInto(out *Stickiness) {
|
||||
func (in *Sticky) DeepCopyInto(out *Sticky) {
|
||||
*out = *in
|
||||
if in.Cookie != nil {
|
||||
in, out := &in.Cookie, &out.Cookie
|
||||
*out = new(Cookie)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Stickiness.
|
||||
func (in *Stickiness) DeepCopy() *Stickiness {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sticky.
|
||||
func (in *Sticky) DeepCopy() *Sticky {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Stickiness)
|
||||
out := new(Sticky)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
@ -1265,3 +1291,45 @@ func (in Users) DeepCopy() Users {
|
|||
in.DeepCopyInto(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.loadBalancer]
|
||||
passHostHeader = true
|
||||
[http.services.Service0.loadBalancer.stickiness]
|
||||
cookieName = "foobar"
|
||||
[http.services.Service0.loadBalancer.sticky.cookie]
|
||||
name = "foobar"
|
||||
|
||||
[[http.services.Service0.loadBalancer.servers]]
|
||||
url = "foobar"
|
||||
|
|
|
@ -142,8 +142,8 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"traefik.http.services.Service0.loadbalancer.responseforwarding.flushinterval": "foobar",
|
||||
"traefik.http.services.Service0.loadbalancer.server.scheme": "foobar",
|
||||
"traefik.http.services.Service0.loadbalancer.server.port": "8080",
|
||||
"traefik.http.services.Service0.loadbalancer.stickiness.cookiename": "foobar",
|
||||
"traefik.http.services.Service0.loadbalancer.stickiness.securecookie": "true",
|
||||
"traefik.http.services.Service0.loadbalancer.sticky.cookie.name": "foobar",
|
||||
"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.name1": "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.server.scheme": "foobar",
|
||||
"traefik.http.services.Service1.loadbalancer.server.port": "8080",
|
||||
"traefik.http.services.Service1.loadbalancer.stickiness": "false",
|
||||
"traefik.http.services.Service1.loadbalancer.stickiness.cookiename": "fui",
|
||||
"traefik.http.services.Service1.loadbalancer.sticky": "false",
|
||||
"traefik.http.services.Service1.loadbalancer.sticky.cookie.name": "fui",
|
||||
"traefik.tcp.routers.Router0.rule": "foobar",
|
||||
"traefik.tcp.routers.Router0.entrypoints": "foobar, fiibar",
|
||||
"traefik.tcp.routers.Router0.service": "foobar",
|
||||
|
@ -510,11 +510,13 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service0": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
Stickiness: &dynamic.Stickiness{
|
||||
CookieName: "foobar",
|
||||
SecureCookie: true,
|
||||
HTTPOnlyCookie: false,
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{
|
||||
Cookie: &dynamic.Cookie{
|
||||
Name: "foobar",
|
||||
Secure: true,
|
||||
HTTPOnly: false,
|
||||
},
|
||||
},
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -541,7 +543,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
Scheme: "foobar",
|
||||
|
@ -908,10 +910,12 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service0": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
Stickiness: &dynamic.Stickiness{
|
||||
CookieName: "foobar",
|
||||
HTTPOnlyCookie: true,
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{
|
||||
Cookie: &dynamic.Cookie{
|
||||
Name: "foobar",
|
||||
HTTPOnly: true,
|
||||
},
|
||||
},
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -938,7 +942,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
Scheme: "foobar",
|
||||
|
@ -1101,9 +1105,9 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"traefik.HTTP.Services.Service0.LoadBalancer.ResponseForwarding.FlushInterval": "foobar",
|
||||
"traefik.HTTP.Services.Service0.LoadBalancer.server.Port": "8080",
|
||||
"traefik.HTTP.Services.Service0.LoadBalancer.server.Scheme": "foobar",
|
||||
"traefik.HTTP.Services.Service0.LoadBalancer.Stickiness.CookieName": "foobar",
|
||||
"traefik.HTTP.Services.Service0.LoadBalancer.Stickiness.HTTPOnlyCookie": "true",
|
||||
"traefik.HTTP.Services.Service0.LoadBalancer.Stickiness.SecureCookie": "false",
|
||||
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Name": "foobar",
|
||||
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.HTTPOnly": "true",
|
||||
"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.name1": "foobar",
|
||||
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Hostname": "foobar",
|
||||
|
|
|
@ -43,7 +43,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{URL: "http://127.0.0.1:8085"},
|
||||
{URL: "http://127.0.0.1:8086"},
|
||||
|
@ -75,7 +75,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{URL: "http://127.0.0.1"},
|
||||
},
|
||||
|
@ -149,7 +149,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:8085",
|
||||
|
@ -167,7 +167,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
|||
},
|
||||
"bar-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:8087",
|
||||
|
@ -222,7 +222,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -293,7 +293,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -337,7 +337,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -389,7 +389,7 @@ func TestPopulateUsedBy(t *testing.T) {
|
|||
Services: map[string]*runtime.ServiceInfo{
|
||||
"foo-service@myprovider": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
|
|
@ -99,7 +99,7 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, container dock
|
|||
|
||||
if len(configuration.Services) == 0 {
|
||||
configuration.Services = make(map[string]*dynamic.Service)
|
||||
lb := &dynamic.LoadBalancerService{}
|
||||
lb := &dynamic.ServersLoadBalancer{}
|
||||
lb.SetDefaults()
|
||||
configuration.Services[serviceName] = &dynamic.Service{
|
||||
LoadBalancer: lb,
|
||||
|
@ -171,7 +171,7 @@ func (p *Provider) addServerTCP(ctx context.Context, container dockerData, loadB
|
|||
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)
|
||||
ip, port, err := p.getIPPort(ctx, container, serverPort)
|
||||
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)
|
||||
}
|
||||
|
||||
func getLBServerPort(loadBalancer *dynamic.LoadBalancerService) string {
|
||||
func getLBServerPort(loadBalancer *dynamic.ServersLoadBalancer) string {
|
||||
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
|
||||
return loadBalancer.Servers[0].Port
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ func TestDefaultRule(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -105,7 +105,7 @@ func TestDefaultRule(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -156,7 +156,7 @@ func TestDefaultRule(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -200,7 +200,7 @@ func TestDefaultRule(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -244,7 +244,7 @@ func TestDefaultRule(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -293,7 +293,7 @@ func TestDefaultRule(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -376,7 +376,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -444,7 +444,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -454,7 +454,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Test2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2:80",
|
||||
|
@ -520,7 +520,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -573,7 +573,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -625,7 +625,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -669,7 +669,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -726,7 +726,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -773,7 +773,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -783,7 +783,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Service2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -990,7 +990,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1042,7 +1042,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1127,7 +1127,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1200,7 +1200,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1292,7 +1292,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1363,7 +1363,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1450,7 +1450,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1526,7 +1526,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1592,7 +1592,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1602,7 +1602,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Test2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2:80",
|
||||
|
@ -1652,7 +1652,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1703,7 +1703,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "h2c://127.0.0.1:8080",
|
||||
|
@ -1749,7 +1749,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -1759,7 +1759,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Service2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:8080",
|
||||
|
@ -1974,7 +1974,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -2035,7 +2035,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -2278,7 +2278,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
http:
|
||||
{{ range $i, $e := until 20 }}
|
||||
routers:
|
||||
{{ range $i, $e := until 20 }}
|
||||
router{{ $e }}:
|
||||
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 (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
|
@ -16,7 +15,6 @@ import (
|
|||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/job"
|
||||
"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/tls"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
@ -136,159 +134,22 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkStringQuoteValidity(value string) error {
|
||||
_, err := strconv.Unquote(`"` + value + `"`)
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
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),
|
||||
},
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New("service not found")
|
||||
for _, middleware := range client.GetMiddlewares() {
|
||||
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
||||
}
|
||||
|
||||
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 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
|
||||
return conf
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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() {
|
||||
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 checkStringQuoteValidity(value string) error {
|
||||
_, err := strconv.Unquote(`"` + value + `"`)
|
||||
return err
|
||||
}
|
||||
|
||||
func makeServiceKey(rule, ingressName string) (string, error) {
|
||||
|
@ -608,50 +228,6 @@ func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bo
|
|||
(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) {
|
||||
secret, exists, err := k8sClient.GetSecret(namespace, secretName)
|
||||
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)
|
||||
|
||||
func Int(v int) *int { return &v }
|
||||
|
||||
func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -671,7 +673,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -720,7 +722,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test2.route-23c7f4c450289ee29016": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -770,7 +772,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test2.route-23c7f4c450289ee29016": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -812,7 +814,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -825,7 +827,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"default/test.route-77c62dfe9517144aeeaa": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
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"},
|
||||
expected: &dynamic.Configuration{
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
|
@ -863,7 +865,21 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"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{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -871,6 +887,77 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
{
|
||||
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",
|
||||
},
|
||||
|
@ -981,7 +1068,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1039,7 +1126,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1097,7 +1184,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1154,7 +1241,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1200,7 +1287,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1246,7 +1333,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1284,7 +1371,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
|
@ -1321,7 +1408,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.5:8443",
|
||||
|
@ -1358,7 +1445,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default/test.route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "https://10.10.0.7:8443",
|
||||
|
|
|
@ -49,6 +49,7 @@ type Service struct {
|
|||
Scheme string `json:"scheme,omitempty"`
|
||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
Weight *int `json:"weight,omitempty"`
|
||||
}
|
||||
|
||||
// MiddlewareRef is a ref to the Middleware resources.
|
||||
|
|
|
@ -395,6 +395,11 @@ func (in *Service) DeepCopyInto(out *Service) {
|
|||
*out = new(HealthCheck)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Weight != nil {
|
||||
in, out := &in.Weight, &out.Weight
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@ func loadService(client Client, namespace string, backend v1beta1.IngressBackend
|
|||
}
|
||||
|
||||
return &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: servers,
|
||||
PassHostHeader: true,
|
||||
},
|
||||
|
|
|
@ -50,7 +50,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -84,7 +84,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -118,7 +118,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -148,7 +148,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -177,7 +177,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/example-com/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -208,7 +208,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -242,7 +242,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -276,7 +276,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -317,7 +317,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -362,7 +362,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -375,7 +375,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"testing/service2/8082": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -428,7 +428,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-backend": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -458,7 +458,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -488,7 +488,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -518,7 +518,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -552,7 +552,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -565,7 +565,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"testing/service1/carotte": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -599,7 +599,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -612,7 +612,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"toto/service1/tchouk": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -664,7 +664,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/8080": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -696,7 +696,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/example-com/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -733,7 +733,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/443": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -763,7 +763,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/8443": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -794,7 +794,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/8443": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -825,7 +825,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-backend": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -855,7 +855,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"testing/service1/80": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
|
|
@ -98,7 +98,7 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, app marathon.A
|
|||
|
||||
if len(conf.Services) == 0 {
|
||||
conf.Services = make(map[string]*dynamic.Service)
|
||||
lb := &dynamic.LoadBalancerService{}
|
||||
lb := &dynamic.ServersLoadBalancer{}
|
||||
lb.SetDefaults()
|
||||
conf.Services[appName] = &dynamic.Service{
|
||||
LoadBalancer: lb,
|
||||
|
|
|
@ -56,7 +56,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {LoadBalancer: &dynamic.LoadBalancerService{
|
||||
"app": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -110,7 +110,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {LoadBalancer: &dynamic.LoadBalancerService{
|
||||
"app": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -156,7 +156,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {LoadBalancer: &dynamic.LoadBalancerService{
|
||||
"app": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -200,7 +200,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {LoadBalancer: &dynamic.LoadBalancerService{
|
||||
"Service1": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:8080",
|
||||
|
@ -249,7 +249,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {LoadBalancer: &dynamic.LoadBalancerService{
|
||||
"Service1": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:8080",
|
||||
|
@ -300,7 +300,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"foo": {LoadBalancer: &dynamic.LoadBalancerService{
|
||||
"foo": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:8080",
|
||||
|
@ -308,7 +308,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
PassHostHeader: true,
|
||||
}},
|
||||
"bar": {LoadBalancer: &dynamic.LoadBalancerService{
|
||||
"bar": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:8081",
|
||||
|
@ -343,7 +343,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -382,7 +382,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {LoadBalancer: &dynamic.LoadBalancerService{
|
||||
"Service1": {LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -420,7 +420,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -451,7 +451,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -495,7 +495,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -529,7 +529,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -539,7 +539,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Service2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -629,7 +629,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -639,7 +639,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"app2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -686,7 +686,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -696,7 +696,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"app2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -734,7 +734,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -744,7 +744,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"app2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -789,7 +789,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -830,7 +830,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -840,7 +840,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"app2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -877,7 +877,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -915,7 +915,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "h2c://localhost:90",
|
||||
|
@ -948,7 +948,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -958,7 +958,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Service2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:8080",
|
||||
|
@ -1123,7 +1123,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -1161,7 +1161,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -1198,7 +1198,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"a_b_app": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
@ -1362,7 +1362,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"bar": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://localhost:80",
|
||||
|
|
|
@ -96,7 +96,7 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, service ranche
|
|||
|
||||
if len(configuration.Services) == 0 {
|
||||
configuration.Services = make(map[string]*dynamic.Service)
|
||||
lb := &dynamic.LoadBalancerService{}
|
||||
lb := &dynamic.ServersLoadBalancer{}
|
||||
lb.SetDefaults()
|
||||
configuration.Services[serviceName] = &dynamic.Service{
|
||||
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)
|
||||
|
||||
serverPort := getLBServerPort(loadBalancer)
|
||||
|
@ -216,7 +216,7 @@ func (p *Provider) addServers(ctx context.Context, service rancherData, loadBala
|
|||
return nil
|
||||
}
|
||||
|
||||
func getLBServerPort(loadBalancer *dynamic.LoadBalancerService) string {
|
||||
func getLBServerPort(loadBalancer *dynamic.ServersLoadBalancer) string {
|
||||
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
|
||||
return loadBalancer.Servers[0].Port
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -95,7 +95,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -105,7 +105,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Test2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.2:80",
|
||||
|
@ -157,7 +157,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -170,7 +170,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Test2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://128.0.0.1:80",
|
||||
|
@ -214,7 +214,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -302,7 +302,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -372,7 +372,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -425,7 +425,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -467,7 +467,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
@ -652,7 +652,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Service1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:80",
|
||||
|
|
|
@ -48,7 +48,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -85,7 +85,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -108,7 +108,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -132,7 +132,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -173,7 +173,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -213,7 +213,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service@provider-1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -236,7 +236,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service@provider-2": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -260,7 +260,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service@provider-1": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -355,7 +355,7 @@ func TestAccessLog(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -383,7 +383,7 @@ func TestAccessLog(t *testing.T) {
|
|||
},
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -448,7 +448,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
desc: "No error",
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1:8085",
|
||||
|
@ -482,7 +482,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
desc: "One router with wrong rule",
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -509,7 +509,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
desc: "All router with wrong rule",
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -536,7 +536,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
desc: "Router with unknown service",
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -579,7 +579,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
desc: "Router with middleware",
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -619,7 +619,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
desc: "Router with unknown middleware",
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -650,7 +650,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
desc: "Router with broken middleware",
|
||||
serviceConfig: map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://127.0.0.1",
|
||||
|
@ -749,7 +749,7 @@ func BenchmarkRouterServe(b *testing.B) {
|
|||
}
|
||||
serviceConfig := map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server.URL,
|
||||
|
@ -793,7 +793,7 @@ func BenchmarkService(b *testing.B) {
|
|||
|
||||
serviceConfig := map[string]*dynamic.Service{
|
||||
"foo-service": {
|
||||
LoadBalancer: &dynamic.LoadBalancerService{
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "tchouck",
|
||||
|
|
|
@ -199,7 +199,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
|||
th.WithRule(routeRule)),
|
||||
),
|
||||
th.WithLoadBalancerServices(th.WithService("bar",
|
||||
th.WithStickiness("test")),
|
||||
th.WithSticky("test")),
|
||||
),
|
||||
)
|
||||
},
|
||||
|
@ -229,7 +229,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
|||
th.WithRule(routeRule)),
|
||||
),
|
||||
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 (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
|
@ -20,6 +21,7 @@ import (
|
|||
"github.com/containous/traefik/v2/pkg/middlewares/pipelining"
|
||||
"github.com/containous/traefik/v2/pkg/server/cookie"
|
||||
"github.com/containous/traefik/v2/pkg/server/internal"
|
||||
"github.com/containous/traefik/v2/pkg/server/service/loadbalancer/wrr"
|
||||
"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)
|
||||
}
|
||||
|
||||
// TODO Should handle multiple service types
|
||||
// FIXME Check if the service is declared multiple times with different types
|
||||
if conf.LoadBalancer == nil {
|
||||
sErr := fmt.Errorf("the service %q doesn't have any load balancer", serviceName)
|
||||
conf.AddError(sErr, true)
|
||||
return nil, sErr
|
||||
if conf.LoadBalancer != nil && conf.Weighted != nil {
|
||||
return nil, errors.New("cannot create service: multi-types service not supported, consider declaring two different pieces of service instead")
|
||||
}
|
||||
|
||||
lb, err := m.getLoadBalancerServiceHandler(ctx, serviceName, conf.LoadBalancer, responseModifier)
|
||||
var lb http.Handler
|
||||
|
||||
switch {
|
||||
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
|
||||
}
|
||||
|
||||
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(
|
||||
ctx context.Context,
|
||||
serviceName string,
|
||||
service *dynamic.LoadBalancerService,
|
||||
service *dynamic.ServersLoadBalancer,
|
||||
responseModifier func(*http.Response) error,
|
||||
) (http.Handler, error) {
|
||||
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.Debug("Creating load-balancer")
|
||||
|
||||
var options []roundrobin.LBOption
|
||||
|
||||
var cookieName string
|
||||
if stickiness := service.Stickiness; stickiness != nil {
|
||||
cookieName = cookie.GetName(stickiness.CookieName, serviceName)
|
||||
opts := roundrobin.CookieOptions{HTTPOnly: stickiness.HTTPOnlyCookie, Secure: stickiness.SecureCookie}
|
||||
if service.Sticky != nil && service.Sticky.Cookie != nil {
|
||||
cookieName = cookie.GetName(service.Sticky.Cookie.Name, serviceName)
|
||||
opts := roundrobin.CookieOptions{HTTPOnly: service.Sticky.Cookie.HTTPOnly, Secure: service.Sticky.Cookie.Secure}
|
||||
options = append(options, roundrobin.EnableStickySession(roundrobin.NewStickySessionWithOptions(cookieName, opts)))
|
||||
logger.Debugf("Sticky session cookie name: %v", cookieName)
|
||||
}
|
||||
|
|
|
@ -27,14 +27,14 @@ func TestGetLoadBalancer(t *testing.T) {
|
|||
testCases := []struct {
|
||||
desc string
|
||||
serviceName string
|
||||
service *dynamic.LoadBalancerService
|
||||
service *dynamic.ServersLoadBalancer
|
||||
fwd http.Handler
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
desc: "Fails when provided an invalid URL",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: ":",
|
||||
|
@ -47,15 +47,15 @@ func TestGetLoadBalancer(t *testing.T) {
|
|||
{
|
||||
desc: "Succeeds when there are no servers",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{},
|
||||
service: &dynamic.ServersLoadBalancer{},
|
||||
fwd: &MockForwarder{},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
desc: "Succeeds when stickiness is set",
|
||||
desc: "Succeeds when sticky.cookie is set",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
Stickiness: &dynamic.Stickiness{},
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||
},
|
||||
fwd: &MockForwarder{},
|
||||
expectError: false,
|
||||
|
@ -114,7 +114,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
|||
testCases := []struct {
|
||||
desc string
|
||||
serviceName string
|
||||
service *dynamic.LoadBalancerService
|
||||
service *dynamic.ServersLoadBalancer
|
||||
responseModifier func(*http.Response) error
|
||||
|
||||
expected []ExpectedResult
|
||||
|
@ -122,7 +122,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
|||
{
|
||||
desc: "Load balances between the two servers",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server1.URL,
|
||||
|
@ -146,7 +146,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
|||
{
|
||||
desc: "StatusBadGateway when the server is not reachable",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://foo",
|
||||
|
@ -162,7 +162,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
|||
{
|
||||
desc: "ServiceUnavailable when no servers are available",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{},
|
||||
},
|
||||
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",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
Stickiness: &dynamic.Stickiness{},
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server1.URL,
|
||||
|
@ -199,8 +199,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
|||
{
|
||||
desc: "Sticky Cookie's options set correctly",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
Stickiness: &dynamic.Stickiness{HTTPOnlyCookie: true, SecureCookie: true},
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{HTTPOnly: true, Secure: true}},
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: server1.URL,
|
||||
|
@ -219,8 +219,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
|||
{
|
||||
desc: "PassHost passes the host instead of the IP",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
Stickiness: &dynamic.Stickiness{},
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||
PassHostHeader: true,
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
|
@ -238,8 +238,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
|
|||
{
|
||||
desc: "PassHost doesn't passe the host instead of the IP",
|
||||
serviceName: "test",
|
||||
service: &dynamic.LoadBalancerService{
|
||||
Stickiness: &dynamic.Stickiness{},
|
||||
service: &dynamic.ServersLoadBalancer{
|
||||
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: serverPassHostFalse.URL,
|
||||
|
@ -297,7 +297,7 @@ func TestManager_Build(t *testing.T) {
|
|||
configs: map[string]*runtime.ServiceInfo{
|
||||
"serviceName": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{},
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -308,7 +308,7 @@ func TestManager_Build(t *testing.T) {
|
|||
configs: map[string]*runtime.ServiceInfo{
|
||||
"serviceName@provider-1": {
|
||||
Service: &dynamic.Service{
|
||||
LoadBalancer: &dynamic.LoadBalancerService{},
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -319,7 +319,7 @@ func TestManager_Build(t *testing.T) {
|
|||
configs: map[string]*runtime.ServiceInfo{
|
||||
"serviceName@provider-1": {
|
||||
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.
|
||||
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) {
|
||||
c.Services = make(map[string]*dynamic.Service)
|
||||
for _, opt := range opts {
|
||||
b := &dynamic.LoadBalancerService{}
|
||||
b := &dynamic.ServersLoadBalancer{}
|
||||
name := opt(b)
|
||||
c.Services[name] = &dynamic.Service{
|
||||
LoadBalancer: b,
|
||||
|
@ -64,8 +64,8 @@ func WithLoadBalancerServices(opts ...func(service *dynamic.LoadBalancerService)
|
|||
}
|
||||
|
||||
// WithService is a helper to create a configuration.
|
||||
func WithService(name string, opts ...func(*dynamic.LoadBalancerService)) func(*dynamic.LoadBalancerService) string {
|
||||
return func(r *dynamic.LoadBalancerService) string {
|
||||
func WithService(name string, opts ...func(*dynamic.ServersLoadBalancer)) func(*dynamic.ServersLoadBalancer) string {
|
||||
return func(r *dynamic.ServersLoadBalancer) string {
|
||||
for _, opt := range opts {
|
||||
opt(r)
|
||||
}
|
||||
|
@ -117,8 +117,8 @@ func WithRule(rule string) func(*dynamic.Router) {
|
|||
}
|
||||
|
||||
// WithServers is a helper to create a configuration.
|
||||
func WithServers(opts ...func(*dynamic.Server)) func(*dynamic.LoadBalancerService) {
|
||||
return func(b *dynamic.LoadBalancerService) {
|
||||
func WithServers(opts ...func(*dynamic.Server)) func(*dynamic.ServersLoadBalancer) {
|
||||
return func(b *dynamic.ServersLoadBalancer) {
|
||||
for _, opt := range opts {
|
||||
server := dynamic.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.
|
||||
func WithStickiness(cookieName string) func(*dynamic.LoadBalancerService) {
|
||||
return func(b *dynamic.LoadBalancerService) {
|
||||
b.Stickiness = &dynamic.Stickiness{
|
||||
CookieName: cookieName,
|
||||
// WithSticky is a helper to create a configuration.
|
||||
func WithSticky(cookieName string) func(*dynamic.ServersLoadBalancer) {
|
||||
return func(b *dynamic.ServersLoadBalancer) {
|
||||
b.Sticky = &dynamic.Sticky{
|
||||
Cookie: &dynamic.Cookie{Name: cookieName},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue