diff --git a/autogen/gentemplates/gen.go b/autogen/gentemplates/gen.go index 60e0022ca..e0f78a0ba 100644 --- a/autogen/gentemplates/gen.go +++ b/autogen/gentemplates/gen.go @@ -754,20 +754,29 @@ func templatesEcsTmpl() (*asset, error) { return a, nil } -var _templatesEurekaTmpl = []byte(`[backends]{{range .Applications}} - {{ $app := .}} - {{range .Instances}} - [backends.backend{{$app.Name}}.servers.server-{{ getInstanceID . }}] - url = "{{ getProtocol . }}://{{ .IpAddr }}:{{ getPort . }}" - weight = {{ getWeight . }} -{{end}}{{end}} +var _templatesEurekaTmpl = []byte(`[backends] +{{range $app := .Applications }} -[frontends]{{range .Applications}} - [frontends.frontend{{.Name}}] - backend = "backend{{.Name}}" + [backends.backend-{{ $app.Name }}] + + {{range $instance := .Instances }} + [backends.backend-{{ $app.Name }}.servers.server-{{ getInstanceID $instance }}] + url = "{{ getProtocol $instance }}://{{ .IpAddr }}:{{ getPort $instance }}" + weight = {{ getWeight $instance }} + {{end}} + +{{end}} + +[frontends] +{{range $app := .Applications }} + + [frontends.frontend-{{ $app.Name }}] + backend = "backend-{{ $app.Name }}" entryPoints = ["http"] - [frontends.frontend{{.Name }}.routes.route-host{{.Name}}] - rule = "Host:{{ .Name | tolower }}" + + [frontends.frontend-{{ $app.Name }}.routes.route-host{{ $app.Name }}] + rule = "Host:{{ $app.Name | tolower }}" + {{end}} `) diff --git a/cmd/traefik/anonymize/anonymize_config_test.go b/cmd/traefik/anonymize/anonymize_config_test.go index ff3a340d2..f44c88b26 100644 --- a/cmd/traefik/anonymize/anonymize_config_test.go +++ b/cmd/traefik/anonymize/anonymize_config_test.go @@ -432,7 +432,7 @@ func TestDo_globalConfiguration(t *testing.T) { DebugLogGeneratedTemplate: true, }, Endpoint: "eureka Endpoint", - Delay: "eureka Delay", + Delay: flaeg.Duration(30 * time.Second), } config.ECS = &ecs.Provider{ BaseProvider: provider.BaseProvider{ diff --git a/cmd/traefik/configuration.go b/cmd/traefik/configuration.go index 2b04e20fb..514510c94 100644 --- a/cmd/traefik/configuration.go +++ b/cmd/traefik/configuration.go @@ -166,7 +166,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration { // default Eureka var defaultEureka eureka.Provider - defaultEureka.Delay = "30s" + defaultEureka.Delay = flaeg.Duration(30 * time.Second) // default ServiceFabric var defaultServiceFabric servicefabric.Provider diff --git a/provider/eureka/config.go b/provider/eureka/config.go index 933a19365..8e27665c8 100644 --- a/provider/eureka/config.go +++ b/provider/eureka/config.go @@ -1,7 +1,6 @@ package eureka import ( - "io/ioutil" "strconv" "text/template" @@ -13,32 +12,21 @@ import ( ) // Build the configuration from Provider server -func (p *Provider) buildConfiguration() (*types.Configuration, error) { - var EurekaFuncMap = template.FuncMap{ +func (p *Provider) buildConfiguration(apps *eureka.Applications) (*types.Configuration, error) { + var eurekaFuncMap = template.FuncMap{ "getPort": getPort, "getProtocol": getProtocol, "getWeight": getWeight, "getInstanceID": getInstanceID, } - eureka.GetLogger().SetOutput(ioutil.Discard) - - client := eureka.NewClient([]string{ - p.Endpoint, - }) - - applications, err := client.GetApplications() - if err != nil { - return nil, err - } - templateObjects := struct { Applications []eureka.Application }{ - applications.Applications, + Applications: apps.Applications, } - configuration, err := p.GetConfiguration("templates/eureka.tmpl", EurekaFuncMap, templateObjects) + configuration, err := p.GetConfiguration("templates/eureka.tmpl", eurekaFuncMap, templateObjects) if err != nil { log.Error(err) } diff --git a/provider/eureka/config_test.go b/provider/eureka/config_test.go index 7d4d538fc..9c029f844 100644 --- a/provider/eureka/config_test.go +++ b/provider/eureka/config_test.go @@ -1,14 +1,16 @@ package eureka import ( + "strconv" "testing" "github.com/ArthurHlt/go-eureka-client/eureka" "github.com/containous/traefik/provider/label" + "github.com/stretchr/testify/assert" ) func TestGetPort(t *testing.T) { - cases := []struct { + testCases := []struct { expectedPort string instanceInfo eureka.InstanceInfo }{ @@ -36,16 +38,19 @@ func TestGetPort(t *testing.T) { }, } - for _, c := range cases { - port := getPort(c.instanceInfo) - if port != c.expectedPort { - t.Fatalf("Should have been %s, got %s", c.expectedPort, port) - } + for i, test := range testCases { + test := test + t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Parallel() + + port := getPort(test.instanceInfo) + assert.Equal(t, test.expectedPort, port) + }) } } func TestGetProtocol(t *testing.T) { - cases := []struct { + testCases := []struct { expectedProtocol string instanceInfo eureka.InstanceInfo }{ @@ -72,16 +77,20 @@ func TestGetProtocol(t *testing.T) { }, }, } - for _, c := range cases { - protocol := getProtocol(c.instanceInfo) - if protocol != c.expectedProtocol { - t.Fatalf("Should have been %s, got %s", c.expectedProtocol, protocol) - } + + for i, test := range testCases { + test := test + t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Parallel() + + protocol := getProtocol(test.instanceInfo) + assert.Equal(t, test.expectedProtocol, protocol) + }) } } func TestGetWeight(t *testing.T) { - cases := []struct { + testCases := []struct { expectedWeight string instanceInfo eureka.InstanceInfo }{ @@ -111,16 +120,19 @@ func TestGetWeight(t *testing.T) { }, } - for _, c := range cases { - weight := getWeight(c.instanceInfo) - if weight != c.expectedWeight { - t.Fatalf("Should have been %s, got %s", c.expectedWeight, weight) - } + for i, test := range testCases { + test := test + t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Parallel() + + weight := getWeight(test.instanceInfo) + assert.Equal(t, test.expectedWeight, weight) + }) } } func TestGetInstanceId(t *testing.T) { - cases := []struct { + testCases := []struct { expectedID string instanceInfo eureka.InstanceInfo }{ @@ -158,10 +170,13 @@ func TestGetInstanceId(t *testing.T) { }, } - for _, c := range cases { - id := getInstanceID(c.instanceInfo) - if id != c.expectedID { - t.Fatalf("Should have been %s, got %s", c.expectedID, id) - } + for i, test := range testCases { + test := test + t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Parallel() + + id := getInstanceID(test.instanceInfo) + assert.Equal(t, test.expectedID, id) + }) } } diff --git a/provider/eureka/eureka.go b/provider/eureka/eureka.go index 37cd4a69c..42c926b6d 100644 --- a/provider/eureka/eureka.go +++ b/provider/eureka/eureka.go @@ -1,9 +1,12 @@ package eureka import ( + "io/ioutil" "time" + "github.com/ArthurHlt/go-eureka-client/eureka" "github.com/cenk/backoff" + "github.com/containous/flaeg" "github.com/containous/traefik/job" "github.com/containous/traefik/log" "github.com/containous/traefik/provider" @@ -14,16 +17,25 @@ import ( // Provider holds configuration of the Provider provider. type Provider struct { provider.BaseProvider `mapstructure:",squash" export:"true"` - Endpoint string `description:"Eureka server endpoint"` - Delay string `description:"Override default configuration time between refresh" export:"true"` + Endpoint string `description:"Eureka server endpoint"` + Delay flaeg.Duration `description:"Override default configuration time between refresh" export:"true"` } // Provide allows the eureka provider to provide configurations to traefik // using the given configuration channel. func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ types.Constraints) error { + eureka.GetLogger().SetOutput(ioutil.Discard) operation := func() error { - configuration, err := p.buildConfiguration() + client := eureka.NewClient([]string{p.Endpoint}) + + applications, err := client.GetApplications() + if err != nil { + log.Errorf("Failed to retrieve applications, error: %s", err) + return err + } + + configuration, err := p.buildConfiguration(applications) if err != nil { log.Errorf("Failed to build configuration for Provider, error: %s", err) return err @@ -34,25 +46,18 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s Configuration: configuration, } - var delay time.Duration - if len(p.Delay) > 0 { - var err error - delay, err = time.ParseDuration(p.Delay) - if err != nil { - log.Errorf("Failed to parse delay for Provider, error: %s", err) - return err - } - } else { - delay = time.Second * 30 - } - - ticker := time.NewTicker(delay) + ticker := time.NewTicker(time.Duration(p.Delay)) safe.Go(func() { for t := range ticker.C { - log.Debugf("Refreshing Provider %s", t.String()) - configuration, err := p.buildConfiguration() + applications, err := client.GetApplications() + if err != nil { + log.Errorf("Failed to retrieve applications, error: %s", err) + continue + } + + configuration, err := p.buildConfiguration(applications) if err != nil { log.Errorf("Failed to refresh Provider configuration, error: %s", err) continue @@ -67,9 +72,6 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s return nil } - notify := func(err error, time time.Duration) { - log.Errorf("Provider connection error %+v, retrying in %s", err, time) - } err := backoff.RetryNotify(operation, job.NewBackOff(backoff.NewExponentialBackOff()), notify) if err != nil { log.Errorf("Cannot connect to Provider server %+v", err) @@ -77,3 +79,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s } return nil } + +func notify(err error, time time.Duration) { + log.Errorf("Provider connection error %+v, retrying in %s", err, time) +} diff --git a/templates/eureka.tmpl b/templates/eureka.tmpl index a2ffbff2e..245b7bdf8 100644 --- a/templates/eureka.tmpl +++ b/templates/eureka.tmpl @@ -1,15 +1,24 @@ -[backends]{{range .Applications}} - {{ $app := .}} - {{range .Instances}} - [backends.backend{{$app.Name}}.servers.server-{{ getInstanceID . }}] - url = "{{ getProtocol . }}://{{ .IpAddr }}:{{ getPort . }}" - weight = {{ getWeight . }} -{{end}}{{end}} +[backends] +{{range $app := .Applications }} + + [backends.backend-{{ $app.Name }}] + + {{range $instance := .Instances }} + [backends.backend-{{ $app.Name }}.servers.server-{{ getInstanceID $instance }}] + url = "{{ getProtocol $instance }}://{{ .IpAddr }}:{{ getPort $instance }}" + weight = {{ getWeight $instance }} + {{end}} + +{{end}} + +[frontends] +{{range $app := .Applications }} + + [frontends.frontend-{{ $app.Name }}] + backend = "backend-{{ $app.Name }}" + entryPoints = ["http"] + + [frontends.frontend-{{ $app.Name }}.routes.route-host{{ $app.Name }}] + rule = "Host:{{ $app.Name | tolower }}" -[frontends]{{range .Applications}} - [frontends.frontend{{.Name}}] - backend = "backend{{.Name}}" - entryPoints = ["http"] - [frontends.frontend{{.Name }}.routes.route-host{{.Name}}] - rule = "Host:{{ .Name | tolower }}" {{end}}