Enhanced flexibility in Consul Catalog configuration
This commit is contained in:
parent
9c27a98821
commit
7d6c778211
6 changed files with 242 additions and 20 deletions
11
docs/toml.md
11
docs/toml.md
|
@ -1320,6 +1320,15 @@ domain = "consul.localhost"
|
||||||
# Optional
|
# Optional
|
||||||
#
|
#
|
||||||
prefix = "traefik"
|
prefix = "traefik"
|
||||||
|
|
||||||
|
# Default frontEnd Rule for Consul services
|
||||||
|
# The format is a Go Template with ".ServiceName", ".Domain" and ".Attributes" available
|
||||||
|
# "getTag(name, tags, defaultValue)", "hasTag(name, tags)" and "getAttribute(name, tags, defaultValue)" functions are available
|
||||||
|
# "getAttribute(...)" function uses prefixed tag names based on "prefix" value
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
#
|
||||||
|
frontEndRule = "Host:{{.ServiceName}}.{{Domain}}"
|
||||||
```
|
```
|
||||||
|
|
||||||
This backend will create routes matching on hostname based on the service name
|
This backend will create routes matching on hostname based on the service name
|
||||||
|
@ -1334,7 +1343,7 @@ Additional settings can be defined using Consul Catalog tags:
|
||||||
- `traefik.backend.loadbalancer=drr`: override the default load balancing mode
|
- `traefik.backend.loadbalancer=drr`: override the default load balancing mode
|
||||||
- `traefik.backend.maxconn.amount=10`: set a maximum number of connections to the backend. Must be used in conjunction with the below label to take effect.
|
- `traefik.backend.maxconn.amount=10`: set a maximum number of connections to the backend. Must be used in conjunction with the below label to take effect.
|
||||||
- `traefik.backend.maxconn.extractorfunc=client.ip`: set the function to be used against the request to determine what to limit maximum connections to the backend by. Must be used in conjunction with the above label to take effect.
|
- `traefik.backend.maxconn.extractorfunc=client.ip`: set the function to be used against the request to determine what to limit maximum connections to the backend by. Must be used in conjunction with the above label to take effect.
|
||||||
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
|
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{{.ServiceName}}.{{.Domain}}`).
|
||||||
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
||||||
- `traefik.frontend.priority=10`: override default frontend priority
|
- `traefik.frontend.priority=10`: override default frontend priority
|
||||||
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||||
|
|
|
@ -7,3 +7,4 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[consulCatalog]
|
[consulCatalog]
|
||||||
domain = "consul.localhost"
|
domain = "consul.localhost"
|
||||||
|
frontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package consul
|
package consul
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -31,7 +32,9 @@ type CatalogProvider struct {
|
||||||
Endpoint string `description:"Consul server endpoint"`
|
Endpoint string `description:"Consul server endpoint"`
|
||||||
Domain string `description:"Default domain used"`
|
Domain string `description:"Default domain used"`
|
||||||
Prefix string `description:"Prefix used for Consul catalog tags"`
|
Prefix string `description:"Prefix used for Consul catalog tags"`
|
||||||
|
FrontEndRule string `description:"Frontend rule used for Consul services"`
|
||||||
client *api.Client
|
client *api.Client
|
||||||
|
frontEndRuleTemplate *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
type serviceUpdate struct {
|
type serviceUpdate struct {
|
||||||
|
@ -137,9 +140,9 @@ func (p *CatalogProvider) healthyNodes(service string) (catalogUpdate, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes := fun.Filter(func(node *api.ServiceEntry) bool {
|
nodes := fun.Filter(func(node *api.ServiceEntry) bool {
|
||||||
constraintTags := p.getContraintTags(node.Service.Tags)
|
constraintTags := p.getConstraintTags(node.Service.Tags)
|
||||||
ok, failingConstraint := p.MatchConstraints(constraintTags)
|
ok, failingConstraint := p.MatchConstraints(constraintTags)
|
||||||
if ok == false && failingConstraint != nil {
|
if !ok && failingConstraint != nil {
|
||||||
log.Debugf("Service %v pruned by '%v' constraint", service, failingConstraint.String())
|
log.Debugf("Service %v pruned by '%v' constraint", service, failingConstraint.String())
|
||||||
}
|
}
|
||||||
return ok
|
return ok
|
||||||
|
@ -162,6 +165,13 @@ func (p *CatalogProvider) healthyNodes(service string) (catalogUpdate, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) getPrefixedName(name string) string {
|
||||||
|
if len(p.Prefix) > 0 {
|
||||||
|
return p.Prefix + "." + name
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
func (p *CatalogProvider) getEntryPoints(list string) []string {
|
func (p *CatalogProvider) getEntryPoints(list string) []string {
|
||||||
return strings.Split(list, ",")
|
return strings.Split(list, ",")
|
||||||
}
|
}
|
||||||
|
@ -172,10 +182,35 @@ func (p *CatalogProvider) getBackend(node *api.ServiceEntry) string {
|
||||||
|
|
||||||
func (p *CatalogProvider) getFrontendRule(service serviceUpdate) string {
|
func (p *CatalogProvider) getFrontendRule(service serviceUpdate) string {
|
||||||
customFrontendRule := p.getAttribute("frontend.rule", service.Attributes, "")
|
customFrontendRule := p.getAttribute("frontend.rule", service.Attributes, "")
|
||||||
if customFrontendRule != "" {
|
if customFrontendRule == "" {
|
||||||
return customFrontendRule
|
customFrontendRule = p.FrontEndRule
|
||||||
}
|
}
|
||||||
return "Host:" + service.ServiceName + "." + p.Domain
|
|
||||||
|
t := p.frontEndRuleTemplate
|
||||||
|
t, err := t.Parse(customFrontendRule)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to parse Consul Catalog custom frontend rule: %s", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
templateObjects := struct {
|
||||||
|
ServiceName string
|
||||||
|
Domain string
|
||||||
|
Attributes []string
|
||||||
|
}{
|
||||||
|
ServiceName: service.ServiceName,
|
||||||
|
Domain: p.Domain,
|
||||||
|
Attributes: service.Attributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = t.Execute(&buffer, templateObjects)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to execute Consul Catalog custom frontend rule template: %s", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CatalogProvider) getBackendAddress(node *api.ServiceEntry) string {
|
func (p *CatalogProvider) getBackendAddress(node *api.ServiceEntry) string {
|
||||||
|
@ -201,22 +236,42 @@ func (p *CatalogProvider) getBackendName(node *api.ServiceEntry, index int) stri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CatalogProvider) getAttribute(name string, tags []string, defaultValue string) string {
|
func (p *CatalogProvider) getAttribute(name string, tags []string, defaultValue string) string {
|
||||||
|
return p.getTag(p.getPrefixedName(name), tags, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) hasTag(name string, tags []string) bool {
|
||||||
|
// Very-very unlikely that a Consul tag would ever start with '=!='
|
||||||
|
tag := p.getTag(name, tags, "=!=")
|
||||||
|
return tag != "=!="
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) getTag(name string, tags []string, defaultValue string) string {
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if strings.Index(strings.ToLower(tag), p.Prefix+".") == 0 {
|
// Given the nature of Consul tags, which could be either singular markers, or key=value pairs, we check if the consul tag starts with 'name'
|
||||||
if kv := strings.SplitN(tag[len(p.Prefix+"."):], "=", 2); len(kv) == 2 && strings.ToLower(kv[0]) == strings.ToLower(name) {
|
if strings.Index(strings.ToLower(tag), strings.ToLower(name)) == 0 {
|
||||||
return kv[1]
|
// In case, where a tag might be a key=value, try to split it by the first '='
|
||||||
|
// - If the first element (which would always be there, even if the tag is a singular marker without '=' in it
|
||||||
|
if kv := strings.SplitN(tag, "=", 2); strings.ToLower(kv[0]) == strings.ToLower(name) {
|
||||||
|
// If the returned result is a key=value pair, return the 'value' component
|
||||||
|
if len(kv) == 2 {
|
||||||
|
return kv[1]
|
||||||
|
}
|
||||||
|
// If the returned result is a singular marker, return the 'key' component
|
||||||
|
return kv[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CatalogProvider) getContraintTags(tags []string) []string {
|
func (p *CatalogProvider) getConstraintTags(tags []string) []string {
|
||||||
var list []string
|
var list []string
|
||||||
|
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if strings.Index(strings.ToLower(tag), p.Prefix+".tags=") == 0 {
|
// If 'AllTagsConstraintFiltering' is disabled, we look for a Consul tag named 'traefik.tags' (unless different 'prefix' is configured)
|
||||||
splitedTags := strings.Split(tag[len(p.Prefix+".tags="):], ",")
|
if strings.Index(strings.ToLower(tag), p.getPrefixedName("tags=")) == 0 {
|
||||||
|
// If 'traefik.tags=' tag is found, take the tag value and split by ',' adding the result to the list to be returned
|
||||||
|
splitedTags := strings.Split(tag[len(p.getPrefixedName("tags=")):], ",")
|
||||||
list = append(list, splitedTags...)
|
list = append(list, splitedTags...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,6 +286,8 @@ func (p *CatalogProvider) buildConfig(catalog []catalogUpdate) *types.Configurat
|
||||||
"getBackendName": p.getBackendName,
|
"getBackendName": p.getBackendName,
|
||||||
"getBackendAddress": p.getBackendAddress,
|
"getBackendAddress": p.getBackendAddress,
|
||||||
"getAttribute": p.getAttribute,
|
"getAttribute": p.getAttribute,
|
||||||
|
"getTag": p.getTag,
|
||||||
|
"hasTag": p.hasTag,
|
||||||
"getEntryPoints": p.getEntryPoints,
|
"getEntryPoints": p.getEntryPoints,
|
||||||
"hasMaxconnAttributes": p.hasMaxconnAttributes,
|
"hasMaxconnAttributes": p.hasMaxconnAttributes,
|
||||||
}
|
}
|
||||||
|
@ -326,6 +383,16 @@ func (p *CatalogProvider) watch(configurationChan chan<- types.ConfigMessage, st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) setupFrontEndTemplate() {
|
||||||
|
var FuncMap = template.FuncMap{
|
||||||
|
"getAttribute": p.getAttribute,
|
||||||
|
"getTag": p.getTag,
|
||||||
|
"hasTag": p.hasTag,
|
||||||
|
}
|
||||||
|
t := template.New("consul catalog frontend rule").Funcs(FuncMap)
|
||||||
|
p.frontEndRuleTemplate = t
|
||||||
|
}
|
||||||
|
|
||||||
// Provide allows the consul catalog provider to provide configurations to traefik
|
// Provide allows the consul catalog provider to provide configurations to traefik
|
||||||
// using the given configuration channel.
|
// using the given configuration channel.
|
||||||
func (p *CatalogProvider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
func (p *CatalogProvider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||||
|
@ -337,6 +404,7 @@ func (p *CatalogProvider) Provide(configurationChan chan<- types.ConfigMessage,
|
||||||
}
|
}
|
||||||
p.client = client
|
p.client = client
|
||||||
p.Constraints = append(p.Constraints, constraints...)
|
p.Constraints = append(p.Constraints, constraints...)
|
||||||
|
p.setupFrontEndTemplate()
|
||||||
|
|
||||||
pool.Go(func(stop chan bool) {
|
pool.Go(func(stop chan bool) {
|
||||||
notify := func(err error, time time.Duration) {
|
notify := func(err error, time time.Duration) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
|
@ -11,9 +12,12 @@ import (
|
||||||
|
|
||||||
func TestConsulCatalogGetFrontendRule(t *testing.T) {
|
func TestConsulCatalogGetFrontendRule(t *testing.T) {
|
||||||
provider := &CatalogProvider{
|
provider := &CatalogProvider{
|
||||||
Domain: "localhost",
|
Domain: "localhost",
|
||||||
Prefix: "traefik",
|
Prefix: "traefik",
|
||||||
|
FrontEndRule: "Host:{{.ServiceName}}.{{.Domain}}",
|
||||||
|
frontEndRuleTemplate: template.New("consul catalog frontend rule"),
|
||||||
}
|
}
|
||||||
|
provider.setupFrontEndTemplate()
|
||||||
|
|
||||||
services := []struct {
|
services := []struct {
|
||||||
service serviceUpdate
|
service serviceUpdate
|
||||||
|
@ -35,12 +39,73 @@ func TestConsulCatalogGetFrontendRule(t *testing.T) {
|
||||||
},
|
},
|
||||||
expected: "Host:*.example.com",
|
expected: "Host:*.example.com",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
service: serviceUpdate{
|
||||||
|
ServiceName: "foo",
|
||||||
|
Attributes: []string{
|
||||||
|
"traefik.frontend.rule=Host:{{.ServiceName}}.example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "Host:foo.example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
service: serviceUpdate{
|
||||||
|
ServiceName: "foo",
|
||||||
|
Attributes: []string{
|
||||||
|
"traefik.frontend.rule=PathPrefix:{{getTag \"contextPath\" .Attributes \"/\"}}",
|
||||||
|
"contextPath=/bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "PathPrefix:/bar",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range services {
|
for _, e := range services {
|
||||||
actual := provider.getFrontendRule(e.service)
|
actual := provider.getFrontendRule(e.service)
|
||||||
if actual != e.expected {
|
if actual != e.expected {
|
||||||
t.Fatalf("expected %q, got %q", e.expected, actual)
|
t.Fatalf("expected %s, got %s", e.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConsulCatalogGetTag(t *testing.T) {
|
||||||
|
provider := &CatalogProvider{
|
||||||
|
Domain: "localhost",
|
||||||
|
Prefix: "traefik",
|
||||||
|
}
|
||||||
|
|
||||||
|
services := []struct {
|
||||||
|
tags []string
|
||||||
|
key string
|
||||||
|
defaultValue string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
tags: []string{
|
||||||
|
"foo.bar=random",
|
||||||
|
"traefik.backend.weight=42",
|
||||||
|
"management",
|
||||||
|
},
|
||||||
|
key: "foo.bar",
|
||||||
|
defaultValue: "0",
|
||||||
|
expected: "random",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := provider.hasTag("management", []string{"management"})
|
||||||
|
if !actual {
|
||||||
|
t.Fatalf("expected %v, got %v", true, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual = provider.hasTag("management", []string{"management=yes"})
|
||||||
|
if !actual {
|
||||||
|
t.Fatalf("expected %v, got %v", true, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range services {
|
||||||
|
actual := provider.getTag(e.key, e.tags, e.defaultValue)
|
||||||
|
if actual != e.expected {
|
||||||
|
t.Fatalf("expected %s, got %s", e.expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,10 +142,71 @@ func TestConsulCatalogGetAttribute(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expected := provider.Prefix + ".foo"
|
||||||
|
actual := provider.getPrefixedName("foo")
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("expected %s, got %s", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
for _, e := range services {
|
for _, e := range services {
|
||||||
actual := provider.getAttribute(e.key, e.tags, e.defaultValue)
|
actual := provider.getAttribute(e.key, e.tags, e.defaultValue)
|
||||||
if actual != e.expected {
|
if actual != e.expected {
|
||||||
t.Fatalf("expected %q, got %q", e.expected, actual)
|
t.Fatalf("expected %s, got %s", e.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConsulCatalogGetAttributeWithEmptyPrefix(t *testing.T) {
|
||||||
|
provider := &CatalogProvider{
|
||||||
|
Domain: "localhost",
|
||||||
|
Prefix: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
services := []struct {
|
||||||
|
tags []string
|
||||||
|
key string
|
||||||
|
defaultValue string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
tags: []string{
|
||||||
|
"foo.bar=ramdom",
|
||||||
|
"backend.weight=42",
|
||||||
|
},
|
||||||
|
key: "backend.weight",
|
||||||
|
defaultValue: "0",
|
||||||
|
expected: "42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tags: []string{
|
||||||
|
"foo.bar=ramdom",
|
||||||
|
"backend.wei=42",
|
||||||
|
},
|
||||||
|
key: "backend.weight",
|
||||||
|
defaultValue: "0",
|
||||||
|
expected: "0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tags: []string{
|
||||||
|
"foo.bar=ramdom",
|
||||||
|
"backend.wei=42",
|
||||||
|
},
|
||||||
|
key: "foo.bar",
|
||||||
|
defaultValue: "random",
|
||||||
|
expected: "ramdom",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := "foo"
|
||||||
|
actual := provider.getPrefixedName("foo")
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("expected %s, got %s", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range services {
|
||||||
|
actual := provider.getAttribute(e.key, e.tags, e.defaultValue)
|
||||||
|
if actual != e.expected {
|
||||||
|
t.Fatalf("expected %s, got %s", e.expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +248,7 @@ func TestConsulCatalogGetBackendAddress(t *testing.T) {
|
||||||
for _, e := range services {
|
for _, e := range services {
|
||||||
actual := provider.getBackendAddress(e.node)
|
actual := provider.getBackendAddress(e.node)
|
||||||
if actual != e.expected {
|
if actual != e.expected {
|
||||||
t.Fatalf("expected %q, got %q", e.expected, actual)
|
t.Fatalf("expected %s, got %s", e.expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,15 +301,17 @@ func TestConsulCatalogGetBackendName(t *testing.T) {
|
||||||
for i, e := range services {
|
for i, e := range services {
|
||||||
actual := provider.getBackendName(e.node, i)
|
actual := provider.getBackendName(e.node, i)
|
||||||
if actual != e.expected {
|
if actual != e.expected {
|
||||||
t.Fatalf("expected %q, got %q", e.expected, actual)
|
t.Fatalf("expected %s, got %s", e.expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConsulCatalogBuildConfig(t *testing.T) {
|
func TestConsulCatalogBuildConfig(t *testing.T) {
|
||||||
provider := &CatalogProvider{
|
provider := &CatalogProvider{
|
||||||
Domain: "localhost",
|
Domain: "localhost",
|
||||||
Prefix: "traefik",
|
Prefix: "traefik",
|
||||||
|
FrontEndRule: "Host:{{.ServiceName}}.{{.Domain}}",
|
||||||
|
frontEndRuleTemplate: template.New("consul catalog frontend rule"),
|
||||||
}
|
}
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
|
|
@ -397,6 +397,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||||
defaultConsulCatalog.Endpoint = "127.0.0.1:8500"
|
defaultConsulCatalog.Endpoint = "127.0.0.1:8500"
|
||||||
defaultConsulCatalog.Constraints = types.Constraints{}
|
defaultConsulCatalog.Constraints = types.Constraints{}
|
||||||
defaultConsulCatalog.Prefix = "traefik"
|
defaultConsulCatalog.Prefix = "traefik"
|
||||||
|
defaultConsulCatalog.FrontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
|
||||||
|
|
||||||
// default Etcd
|
// default Etcd
|
||||||
var defaultEtcd etcd.Provider
|
var defaultEtcd etcd.Provider
|
||||||
|
|
|
@ -857,6 +857,21 @@
|
||||||
#
|
#
|
||||||
# prefix = "traefik"
|
# prefix = "traefik"
|
||||||
|
|
||||||
|
# Default frontEnd Rule for Consul services
|
||||||
|
# - The format is a Go Template with ".ServiceName", ".Domain" and ".Attributes" available
|
||||||
|
# -- "getTag(name, tags, defaultValue)", "hasTag(name, tags)" and "getAttribute(name, tags, defaultValue)" functions are available
|
||||||
|
# --- "getAttribute(...)" function uses prefixed tag names based on "prefix" value
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
#
|
||||||
|
#frontEndRule = "Host:{{.ServiceName}}.{{Domain}}"
|
||||||
|
|
||||||
|
# Should use all Consul catalog tags for constraint filtering
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
#
|
||||||
|
#allTagsConstraintFiltering = false
|
||||||
|
|
||||||
# Constraints
|
# Constraints
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
|
|
Loading…
Reference in a new issue