Allow configuring server URLs with label providers

This commit is contained in:
Taylor Yelverton 2025-01-09 10:20:06 -06:00 committed by GitHub
parent b0a72960bc
commit 95dd17e020
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 924 additions and 48 deletions

View File

@ -204,7 +204,9 @@
- "traefik.http.services.service02.loadbalancer.sticky.cookie.samesite=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.secure=true"
- "traefik.http.services.service02.loadbalancer.server.port=foobar"
- "traefik.http.services.service02.loadbalancer.server.preservepath=true"
- "traefik.http.services.service02.loadbalancer.server.scheme=foobar"
- "traefik.http.services.service02.loadbalancer.server.url=foobar"
- "traefik.http.services.service02.loadbalancer.server.weight=42"
- "traefik.tcp.middlewares.tcpmiddleware01.ipallowlist.sourcerange=foobar, foobar"
- "traefik.tcp.middlewares.tcpmiddleware02.ipwhitelist.sourcerange=foobar, foobar"

View File

@ -168,6 +168,15 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
traefik.http.services.myservice.loadbalancer.server.scheme=http
```
??? info "`traefik.http.services.<service_name>.loadbalancer.server.url`"
Defines the service URL.
This option cannot be used in combination with `port` or `scheme` definition.
```yaml
traefik.http.services.myservice.loadbalancer.server.url=http://foobar:8080
```
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.

View File

@ -283,6 +283,15 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.server.scheme=http"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.server.url`"
Defines the service URL.
This option cannot be used in combination with `port` or `scheme` definition.
```yaml
- "traefik.http.services.myservice.loadbalancer.server.url=http://foobar:8080"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.

View File

@ -170,6 +170,15 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
traefik.http.services.myservice.loadbalancer.server.scheme=http
```
??? info "`traefik.http.services.<service_name>.loadbalancer.server.url`"
Defines the service URL.
This option cannot be used in combination with `port` or `scheme` definition.
```yaml
traefik.http.services.myservice.loadbalancer.server.url=http://foobar:8080
```
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.

View File

@ -168,6 +168,15 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
traefik.http.services.myservice.loadbalancer.server.scheme=http
```
??? info "`traefik.http.services.<service_name>.loadbalancer.server.url`"
Defines the service URL.
This option cannot be used in combination with `port` or `scheme` definition.
```yaml
traefik.http.services.myservice.loadbalancer.server.url=http://foobar:8080
```
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.

View File

@ -297,6 +297,15 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.server.scheme=http"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.server.url`"
Defines the service URL.
This option cannot be used in combination with `port` or `scheme` definition.
```yaml
- "traefik.http.services.myservice.loadbalancer.server.url=http://foobar:8080"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.

View File

@ -170,8 +170,6 @@ func (s *ConsulCatalogSuite) TestByLabels() {
Tags: []string{
"traefik.enable=true",
"traefik.http.routers.router1.rule=Path(`/whoami`)",
"traefik.http.routers.router1.service=service1",
"traefik.http.services.service1.loadBalancer.server.url=http://" + containerIP,
},
Port: 80,
Address: containerIP,
@ -576,8 +574,6 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck() {
tags := []string{
"traefik.enable=true",
"traefik.http.routers.router1.rule=Path(`/whoami`)",
"traefik.http.routers.router1.service=service1",
"traefik.http.services.service1.loadBalancer.server.url=http://" + whoamiIP,
}
reg1 := &api.AgentServiceRegistration{
@ -658,8 +654,6 @@ func (s *ConsulCatalogSuite) TestConsulConnect() {
"traefik.enable=true",
"traefik.consulcatalog.connect=true",
"traefik.http.routers.router1.rule=Path(`/`)",
"traefik.http.routers.router1.service=service1",
"traefik.http.services.service1.loadBalancer.server.url=https://" + connectIP,
},
Connect: &api.AgentServiceConnect{
Native: true,
@ -718,8 +712,6 @@ func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault() {
Tags: []string{
"traefik.enable=true",
"traefik.http.routers.router1.rule=Path(`/`)",
"traefik.http.routers.router1.service=service1",
"traefik.http.services.service1.loadBalancer.server.url=https://" + connectIP,
},
Connect: &api.AgentServiceConnect{
Native: true,
@ -800,8 +792,6 @@ func (s *ConsulCatalogSuite) TestConsulConnect_NotAware() {
"traefik.enable=true",
"traefik.consulcatalog.connect=true",
"traefik.http.routers.router1.rule=Path(`/`)",
"traefik.http.routers.router1.service=service1",
"traefik.http.services.service1.loadBalancer.server.url=https://" + connectIP,
},
Connect: &api.AgentServiceConnect{
Native: true,

View File

@ -270,17 +270,13 @@ func (r *ResponseForwarding) SetDefaults() {
// Server holds the server configuration.
type Server struct {
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" label:"weight" export:"true"`
PreservePath bool `json:"preservePath,omitempty" toml:"preservePath,omitempty" yaml:"preservePath,omitempty" label:"-" export:"true"`
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty"`
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" export:"true"`
PreservePath bool `json:"preservePath,omitempty" toml:"preservePath,omitempty" yaml:"preservePath,omitempty" export:"true"`
Fenced bool `json:"fenced,omitempty" toml:"-" yaml:"-" label:"-" file:"-" kv:"-"`
Scheme string `json:"-" toml:"-" yaml:"-" file:"-"`
Port string `json:"-" toml:"-" yaml:"-" file:"-"`
}
// SetDefaults Default values for a Server.
func (s *Server) SetDefaults() {
s.Scheme = "http"
// Scheme can only be defined with label Providers.
Scheme string `json:"-" toml:"-" yaml:"-" file:"-" kv:"-"`
Port string `json:"-" toml:"-" yaml:"-" file:"-" kv:"-"`
}
// +k8s:deepcopy-gen=true

View File

@ -171,6 +171,8 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.http.services.Service0.loadbalancer.healthcheck.followredirects": "true",
"traefik.http.services.Service0.loadbalancer.passhostheader": "true",
"traefik.http.services.Service0.loadbalancer.responseforwarding.flushinterval": "1s",
"traefik.http.services.Service0.loadbalancer.server.url": "foobar",
"traefik.http.services.Service0.loadbalancer.server.preservepath": "true",
"traefik.http.services.Service0.loadbalancer.server.scheme": "foobar",
"traefik.http.services.Service0.loadbalancer.server.port": "8080",
"traefik.http.services.Service0.loadbalancer.sticky.cookie.name": "foobar",
@ -191,6 +193,8 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.healthcheck.followredirects": "true",
"traefik.http.services.Service1.loadbalancer.passhostheader": "true",
"traefik.http.services.Service1.loadbalancer.responseforwarding.flushinterval": "1s",
"traefik.http.services.Service1.loadbalancer.server.url": "foobar",
"traefik.http.services.Service1.loadbalancer.server.preservepath": "true",
"traefik.http.services.Service1.loadbalancer.server.scheme": "foobar",
"traefik.http.services.Service1.loadbalancer.server.port": "8080",
"traefik.http.services.Service1.loadbalancer.sticky": "false",
@ -683,8 +687,10 @@ func TestDecodeConfiguration(t *testing.T) {
},
Servers: []dynamic.Server{
{
Scheme: "foobar",
Port: "8080",
URL: "foobar",
PreservePath: true,
Scheme: "foobar",
Port: "8080",
},
},
HealthCheck: &dynamic.ServerHealthCheck{
@ -714,8 +720,10 @@ func TestDecodeConfiguration(t *testing.T) {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
Scheme: "foobar",
Port: "8080",
URL: "foobar",
PreservePath: true,
Scheme: "foobar",
Port: "8080",
},
},
HealthCheck: &dynamic.ServerHealthCheck{
@ -1218,8 +1226,10 @@ func TestEncodeConfiguration(t *testing.T) {
},
Servers: []dynamic.Server{
{
Scheme: "foobar",
Port: "8080",
URL: "foobar",
PreservePath: true,
Scheme: "foobar",
Port: "8080",
},
},
HealthCheck: &dynamic.ServerHealthCheck{
@ -1247,8 +1257,10 @@ func TestEncodeConfiguration(t *testing.T) {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
Scheme: "foobar",
Port: "8080",
URL: "foobar",
PreservePath: true,
Scheme: "foobar",
Port: "8080",
},
},
HealthCheck: &dynamic.ServerHealthCheck{
@ -1454,6 +1466,8 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Timeout": "1000000000",
"traefik.HTTP.Services.Service0.LoadBalancer.PassHostHeader": "true",
"traefik.HTTP.Services.Service0.LoadBalancer.ResponseForwarding.FlushInterval": "1000000000",
"traefik.HTTP.Services.Service0.LoadBalancer.server.URL": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.server.PreservePath": "true",
"traefik.HTTP.Services.Service0.LoadBalancer.server.Port": "8080",
"traefik.HTTP.Services.Service0.LoadBalancer.server.Scheme": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Name": "foobar",
@ -1474,6 +1488,8 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Timeout": "1000000000",
"traefik.HTTP.Services.Service1.LoadBalancer.PassHostHeader": "true",
"traefik.HTTP.Services.Service1.LoadBalancer.ResponseForwarding.FlushInterval": "1000000000",
"traefik.HTTP.Services.Service1.LoadBalancer.server.URL": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.server.PreservePath": "true",
"traefik.HTTP.Services.Service1.LoadBalancer.server.Port": "8080",
"traefik.HTTP.Services.Service1.LoadBalancer.server.Scheme": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.ServersTransport": "foobar",

View File

@ -272,16 +272,20 @@ func (p *Provider) addServer(item itemData, loadBalancer *dynamic.ServersLoadBal
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.Server{}
server.SetDefaults()
loadBalancer.Servers = []dynamic.Server{server}
loadBalancer.Servers = []dynamic.Server{{}}
}
if item.Address == "" {
return errors.New("address is missing")
}
if loadBalancer.Servers[0].URL != "" {
if loadBalancer.Servers[0].Scheme != "" || loadBalancer.Servers[0].Port != "" {
return errors.New("defining scheme or port is not allowed when URL is defined")
}
return nil
}
port := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
@ -295,6 +299,9 @@ func (p *Provider) addServer(item itemData, loadBalancer *dynamic.ServersLoadBal
scheme := loadBalancer.Servers[0].Scheme
loadBalancer.Servers[0].Scheme = ""
if scheme == "" {
scheme = "http"
}
if item.ExtraConf.ConsulCatalog.Connect {
loadBalancer.ServersTransport = itemServersTransportKey(item)

View File

@ -1923,6 +1923,194 @@ func Test_buildConfiguration(t *testing.T) {
},
},
},
{
desc: "one container with label url",
items: []itemData{
{
ID: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
},
Address: "127.0.0.1",
Port: "80",
Status: api.HealthPassing,
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Service1",
Rule: "Host(`Test.traefik.wtf`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://1.2.3.4:5678",
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and preserve path",
items: []itemData{
{
ID: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.preservepath": "true",
},
Address: "127.0.0.1",
Port: "80",
Status: api.HealthPassing,
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Service1",
Rule: "Host(`Test.traefik.wtf`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://1.2.3.4:5678",
PreservePath: true,
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and port",
items: []itemData{
{
ID: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.port": "1234",
},
Address: "127.0.0.1",
Port: "80",
Status: api.HealthPassing,
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and scheme",
items: []itemData{
{
ID: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.scheme": "https",
},
Address: "127.0.0.1",
Port: "80",
Status: api.HealthPassing,
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label port on two services",
items: []itemData{

View File

@ -262,10 +262,14 @@ func (p *DynConfBuilder) addServer(ctx context.Context, container dockerData, lo
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.Server{}
server.SetDefaults()
loadBalancer.Servers = []dynamic.Server{{}}
}
loadBalancer.Servers = []dynamic.Server{server}
if loadBalancer.Servers[0].URL != "" {
if loadBalancer.Servers[0].Scheme != "" || loadBalancer.Servers[0].Port != "" {
return errors.New("defining scheme or port is not allowed when URL is defined")
}
return nil
}
serverPort := loadBalancer.Servers[0].Port
@ -280,8 +284,13 @@ func (p *DynConfBuilder) addServer(ctx context.Context, container dockerData, lo
return errors.New("port is missing")
}
loadBalancer.Servers[0].URL = fmt.Sprintf("%s://%s", loadBalancer.Servers[0].Scheme, net.JoinHostPort(ip, port))
scheme := loadBalancer.Servers[0].Scheme
loadBalancer.Servers[0].Scheme = ""
if scheme == "" {
scheme = "http"
}
loadBalancer.Servers[0].URL = fmt.Sprintf("%s://%s", scheme, net.JoinHostPort(ip, port))
return nil
}

View File

@ -2362,6 +2362,226 @@ func TestDynConfBuilder_build(t *testing.T) {
},
},
},
{
desc: "one container with label url",
containers: []dockerData{
{
ServiceName: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("4567/tcp"): []nat.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
Name: "bridge",
Addr: "127.0.0.1",
},
},
},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Service1",
Rule: "Host(`Test.traefik.wtf`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://1.2.3.4:5678",
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and preserve path",
containers: []dockerData{
{
ServiceName: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.preservepath": "true",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("4567/tcp"): []nat.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
Name: "bridge",
Addr: "127.0.0.1",
},
},
},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Service1",
Rule: "Host(`Test.traefik.wtf`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://1.2.3.4:5678",
PreservePath: true,
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and port",
containers: []dockerData{
{
ServiceName: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.port": "1234",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("4567/tcp"): []nat.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
Name: "bridge",
Addr: "127.0.0.1",
},
},
},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and scheme",
containers: []dockerData{
{
ServiceName: "Test",
Name: "Test",
Labels: map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.scheme": "https",
},
NetworkSettings: networkSettings{
Ports: nat.PortMap{
nat.Port("4567/tcp"): []nat.PortBinding{},
},
Networks: map[string]*networkData{
"bridge": {
Name: "bridge",
Addr: "127.0.0.1",
},
},
},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container without port",
containers: []dockerData{

View File

@ -252,10 +252,14 @@ func (p *Provider) addServer(instance ecsInstance, loadBalancer *dynamic.Servers
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.Server{}
server.SetDefaults()
loadBalancer.Servers = []dynamic.Server{{}}
}
loadBalancer.Servers = []dynamic.Server{server}
if loadBalancer.Servers[0].URL != "" {
if loadBalancer.Servers[0].Scheme != "" || loadBalancer.Servers[0].Port != "" {
return errors.New("defining scheme or port is not allowed when URL is defined")
}
return nil
}
serverPort := loadBalancer.Servers[0].Port
@ -270,8 +274,13 @@ func (p *Provider) addServer(instance ecsInstance, loadBalancer *dynamic.Servers
return errors.New("port is missing")
}
loadBalancer.Servers[0].URL = fmt.Sprintf("%s://%s", loadBalancer.Servers[0].Scheme, net.JoinHostPort(ip, port))
scheme := loadBalancer.Servers[0].Scheme
loadBalancer.Servers[0].Scheme = ""
if scheme == "" {
scheme = "http"
}
loadBalancer.Servers[0].URL = fmt.Sprintf("%s://%s", scheme, net.JoinHostPort(ip, port))
return nil
}

View File

@ -2057,6 +2057,206 @@ func Test_buildConfiguration(t *testing.T) {
},
},
},
{
desc: "one container with label url",
containers: []ecsInstance{
instance(
name("Test"),
labels(map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
}),
iMachine(
mState(ec2.InstanceStateNameRunning),
mPrivateIP("127.0.0.1"),
mPorts(
mPort(80, 8080, "tcp"),
),
),
),
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Service1",
Rule: "Host(`Test.traefik.wtf`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://1.2.3.4:5678",
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and preserve path",
containers: []ecsInstance{
instance(
name("Test"),
labels(map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.preservepath": "true",
}),
iMachine(
mState(ec2.InstanceStateNameRunning),
mPrivateIP("127.0.0.1"),
mPorts(
mPort(80, 8080, "tcp"),
),
),
),
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Service1",
Rule: "Host(`Test.traefik.wtf`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://1.2.3.4:5678",
PreservePath: true,
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and port",
containers: []ecsInstance{
instance(
name("Test"),
labels(map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.port": "1234",
}),
iMachine(
mState(ec2.InstanceStateNameRunning),
mPrivateIP("127.0.0.1"),
mPorts(
mPort(80, 8080, "tcp"),
),
),
),
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label url and scheme",
containers: []ecsInstance{
instance(
name("Test"),
labels(map[string]string{
"traefik.http.services.Service1.LoadBalancer.server.url": "http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.scheme": "https",
}),
iMachine(
mState(ec2.InstanceStateNameRunning),
mPrivateIP("127.0.0.1"),
mPorts(
mPort(80, 8080, "tcp"),
),
),
),
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one container with label port not exposed by container",
containers: []ecsInstance{

View File

@ -654,12 +654,10 @@ func Test_buildConfiguration(t *testing.T) {
},
Servers: []dynamic.Server{
{
URL: "foobar",
Scheme: "http",
URL: "foobar",
},
{
URL: "foobar",
Scheme: "http",
URL: "foobar",
},
},
HealthCheck: &dynamic.ServerHealthCheck{

View File

@ -241,16 +241,20 @@ func (p *Provider) addServer(i item, lb *dynamic.ServersLoadBalancer) error {
}
if len(lb.Servers) == 0 {
server := dynamic.Server{}
server.SetDefaults()
lb.Servers = []dynamic.Server{server}
lb.Servers = []dynamic.Server{{}}
}
if i.Address == "" {
return errors.New("address is missing")
}
if lb.Servers[0].URL != "" {
if lb.Servers[0].Scheme != "" || lb.Servers[0].Port != "" {
return errors.New("defining scheme or port is not allowed when URL is defined")
}
return nil
}
port := lb.Servers[0].Port
lb.Servers[0].Port = ""
@ -264,6 +268,10 @@ func (p *Provider) addServer(i item, lb *dynamic.ServersLoadBalancer) error {
scheme := lb.Servers[0].Scheme
lb.Servers[0].Scheme = ""
if scheme == "" {
scheme = "http"
}
lb.Servers[0].URL = fmt.Sprintf("%s://%s", scheme, net.JoinHostPort(i.Address, port))
return nil

View File

@ -1551,6 +1551,194 @@ func Test_buildConfig(t *testing.T) {
},
},
},
{
desc: "one service with label url",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.http.services.Service1.LoadBalancer.server.url = http://1.2.3.4:5678",
},
Address: "127.0.0.1",
Port: 9999,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Service1",
Rule: "Host(`Test.traefik.test`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://1.2.3.4:5678",
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one service with label url and preserve path",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.http.services.Service1.LoadBalancer.server.url = http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.preservepath = true",
},
Address: "127.0.0.1",
Port: 9999,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"Test": {
Service: "Service1",
Rule: "Host(`Test.traefik.test`)",
DefaultRule: true,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"Service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://1.2.3.4:5678",
PreservePath: true,
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one service with label url and port",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.http.services.Service1.LoadBalancer.server.url = http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.port = 1234",
},
Address: "127.0.0.1",
Port: 9999,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one service with label url and scheme",
items: []item{
{
ID: "id1",
Name: "Test",
Tags: []string{
"traefik.http.services.Service1.LoadBalancer.server.url = http://1.2.3.4:5678",
"traefik.http.services.Service1.LoadBalancer.server.scheme = https",
},
Address: "127.0.0.1",
Port: 9999,
ExtraConf: configuration{Enable: true},
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Stores: map[string]tls.Store{},
},
},
},
{
desc: "one service with label port on two services",
items: []item{