Support multiple namespaces for Consul and ConsulCatalog providers

Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
Romain 2022-06-03 12:00:09 +02:00 committed by GitHub
parent f352c34136
commit f90e3817e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 531 additions and 152 deletions

View file

@ -174,6 +174,8 @@
"SA1019: cfg.SSLHost is deprecated", "SA1019: cfg.SSLHost is deprecated",
"SA1019: cfg.SSLForceHost is deprecated", "SA1019: cfg.SSLForceHost is deprecated",
"SA1019: cfg.FeaturePolicy is deprecated", "SA1019: cfg.FeaturePolicy is deprecated",
"SA1019: c.Providers.ConsulCatalog.Namespace is deprecated",
"SA1019: c.Providers.Consul.Namespace is deprecated",
] ]
[[issues.exclude-rules]] [[issues.exclude-rules]]
path = "(.+)_test.go" path = "(.+)_test.go"

View file

@ -3,9 +3,10 @@
This page is maintained and updated periodically to reflect our roadmap and any decisions around feature deprecation. This page is maintained and updated periodically to reflect our roadmap and any decisions around feature deprecation.
| Feature | Deprecated | End of Support | Removal | | Feature | Deprecated | End of Support | Removal |
|-------------------------------------------------------|------------|----------------|---------| |---------------------------------------------------------------|------------|----------------|---------|
| [Pilot Dashboard (Metrics)](#pilot-dashboard-metrics) | 2.7 | 2.8 | 2.9 | | [Pilot Dashboard (Metrics)](#pilot-dashboard-metrics) | 2.7 | 2.8 | 2.9 |
| [Pilot Plugins](#pilot-plugins) | 2.7 | 2.8 | 2.9 | | [Pilot Plugins](#pilot-plugins) | 2.7 | 2.8 | 2.9 |
| [Consul Enterprise Namespaces](#consul-enterprise-namespaces) | 2.8 | TBD | TBD |
## Impact ## Impact
@ -18,3 +19,8 @@ In 2.9, the Pilot platform and all Traefik integration code will be permanently
Starting on 2.7 the pilot token will not be a requirement anymore. Starting on 2.7 the pilot token will not be a requirement anymore.
At 2.9, a new plugin catalog home should be available, decoupled from pilot. At 2.9, a new plugin catalog home should be available, decoupled from pilot.
### Consul Enterprise Namespaces
Starting on 2.8 the `namespace` option of Consul and Consul Catalog providers is deprecated,
please use the `namespaces` options instead.

View file

@ -464,3 +464,7 @@ In `v2.6.1`, the Datadog tags added to a span changed from `service.name` to `tr
In `v2.8`, the `caOptional` option is deprecated as TLS client authentication is a server side option. In `v2.8`, the `caOptional` option is deprecated as TLS client authentication is a server side option.
This option available in the ForwardAuth middleware, as well as in the HTTP, Consul, Etcd, Redis, ZooKeeper, Marathon, Consul Catalog, and Docker providers has no effect and must not be used anymore. This option available in the ForwardAuth middleware, as well as in the HTTP, Consul, Etcd, Redis, ZooKeeper, Marathon, Consul Catalog, and Docker providers has no effect and must not be used anymore.
### Consul Enterprise Namespaces
In `v2.8`, the `namespace` option of Consul and Consul Catalog providers is deprecated, please use the `namespaces` options instead.

View file

@ -525,7 +525,7 @@ providers:
``` ```
```bash tab="CLI" ```bash tab="CLI"
--providers.consulcatalog.defaultRule="Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" --providers.consulcatalog.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)
# ... # ...
``` ```
@ -669,6 +669,8 @@ For additional information, refer to [Restrict the Scope of Service Discovery](.
### `namespace` ### `namespace`
??? warning "Deprecated in favor of the [`namespaces`](#namespaces) option."
_Optional, Default=""_ _Optional, Default=""_
The `namespace` option defines the namespace in which the consul catalog services will be discovered. The `namespace` option defines the namespace in which the consul catalog services will be discovered.
@ -678,6 +680,10 @@ The `namespace` option defines the namespace in which the consul catalog service
The namespace option only works with [Consul Enterprise](https://www.consul.io/docs/enterprise), The namespace option only works with [Consul Enterprise](https://www.consul.io/docs/enterprise),
which provides the [Namespaces](https://www.consul.io/docs/enterprise/namespaces) feature. which provides the [Namespaces](https://www.consul.io/docs/enterprise/namespaces) feature.
!!! warning
One should only define either the `namespaces` option or the `namespace` option.
```yaml tab="File (YAML)" ```yaml tab="File (YAML)"
providers: providers:
consulCatalog: consulCatalog:
@ -696,6 +702,46 @@ providers:
# ... # ...
``` ```
### `namespaces`
_Optional, Default=""_
The `namespaces` option defines the namespaces in which the consul catalog services will be discovered.
When using the `namespaces` option, the discovered configuration object names will be suffixed as shown below:
```text
<resource-name>@consulcatalog-<namespace>
```
!!! warning
The namespaces option only works with [Consul Enterprise](https://www.consul.io/docs/enterprise),
which provides the [Namespaces](https://www.consul.io/docs/enterprise/namespaces) feature.
!!! warning
One should only define either the `namespaces` option or the `namespace` option.
```yaml tab="File (YAML)"
providers:
consulCatalog:
namespaces:
- "ns1"
- "ns2"
# ...
```
```toml tab="File (TOML)"
[providers.consulCatalog]
namespaces = ["ns1", "ns2"]
# ...
```
```bash tab="CLI"
--providers.consulcatalog.namespaces=ns1,ns2
# ...
```
### `watch` ### `watch`
_Optional, Default=false_ _Optional, Default=false_

View file

@ -61,6 +61,8 @@ providers:
### `namespace` ### `namespace`
??? warning "Deprecated in favor of the [`namespaces`](#namespaces) option."
_Optional, Default=""_ _Optional, Default=""_
The `namespace` option defines the namespace to query. The `namespace` option defines the namespace to query.
@ -70,6 +72,10 @@ The `namespace` option defines the namespace to query.
The namespace option only works with [Consul Enterprise](https://www.consul.io/docs/enterprise), The namespace option only works with [Consul Enterprise](https://www.consul.io/docs/enterprise),
which provides the [Namespaces](https://www.consul.io/docs/enterprise/namespaces) feature. which provides the [Namespaces](https://www.consul.io/docs/enterprise/namespaces) feature.
!!! warning
One should only define either the `namespaces` option or the `namespace` option.
```yaml tab="File (YAML)" ```yaml tab="File (YAML)"
providers: providers:
consul: consul:
@ -87,6 +93,46 @@ providers:
--providers.consul.namespace=production --providers.consul.namespace=production
``` ```
### `namespaces`
_Optional, Default=""_
The `namespaces` option defines the namespaces to query.
When using the `namespaces` option, the discovered configuration object names will be suffixed as shown below:
```text
<resource-name>@consul-<namespace>
```
!!! warning
The namespaces option only works with [Consul Enterprise](https://www.consul.io/docs/enterprise),
which provides the [Namespaces](https://www.consul.io/docs/enterprise/namespaces) feature.
!!! warning
One should only define either the `namespaces` option or the `namespace` option.
```yaml tab="File (YAML)"
providers:
consul:
namespaces:
- "ns1"
- "ns2"
# ...
```
```toml tab="File (TOML)"
[providers.consul]
namespaces = ["ns1", "ns2"]
# ...
```
```bash tab="CLI"
--providers.consul.namespaces=ns1,ns2
# ...
```
### `username` ### `username`
_Optional, Default=""_ _Optional, Default=""_

View file

@ -403,7 +403,10 @@ Enable Consul backend with default settings. (Default: ```false```)
KV store endpoints (Default: ```127.0.0.1:8500```) KV store endpoints (Default: ```127.0.0.1:8500```)
`--providers.consul.namespace`: `--providers.consul.namespace`:
KV Namespace Sets the namespace used to discover the configuration (Consul Enterprise only).
`--providers.consul.namespaces`:
Sets the namespaces used to discover the configuration (Consul Enterprise only).
`--providers.consul.password`: `--providers.consul.password`:
KV Password KV Password
@ -492,11 +495,14 @@ Expose containers by default. (Default: ```true```)
`--providers.consulcatalog.namespace`: `--providers.consulcatalog.namespace`:
Sets the namespace used to discover services (Consul Enterprise only). Sets the namespace used to discover services (Consul Enterprise only).
`--providers.consulcatalog.namespaces`:
Sets the namespaces used to discover services (Consul Enterprise only).
`--providers.consulcatalog.prefix`: `--providers.consulcatalog.prefix`:
Prefix for consul service tags. Default 'traefik' (Default: ```traefik```) Prefix for consul service tags. (Default: ```traefik```)
`--providers.consulcatalog.refreshinterval`: `--providers.consulcatalog.refreshinterval`:
Interval for check Consul API. Default 15s (Default: ```15```) Interval for check Consul API. (Default: ```15```)
`--providers.consulcatalog.requireconsistent`: `--providers.consulcatalog.requireconsistent`:
Forces the read to be fully consistent. (Default: ```false```) Forces the read to be fully consistent. (Default: ```false```)
@ -594,9 +600,6 @@ Enable Etcd backend with default settings. (Default: ```false```)
`--providers.etcd.endpoints`: `--providers.etcd.endpoints`:
KV store endpoints (Default: ```127.0.0.1:2379```) KV store endpoints (Default: ```127.0.0.1:2379```)
`--providers.etcd.namespace`:
KV Namespace
`--providers.etcd.password`: `--providers.etcd.password`:
KV Password KV Password
@ -858,9 +861,6 @@ Enable Redis backend with default settings. (Default: ```false```)
`--providers.redis.endpoints`: `--providers.redis.endpoints`:
KV store endpoints (Default: ```127.0.0.1:6379```) KV store endpoints (Default: ```127.0.0.1:6379```)
`--providers.redis.namespace`:
KV Namespace
`--providers.redis.password`: `--providers.redis.password`:
KV Password KV Password
@ -900,9 +900,6 @@ Enable ZooKeeper backend with default settings. (Default: ```false```)
`--providers.zookeeper.endpoints`: `--providers.zookeeper.endpoints`:
KV store endpoints (Default: ```127.0.0.1:2181```) KV store endpoints (Default: ```127.0.0.1:2181```)
`--providers.zookeeper.namespace`:
KV Namespace
`--providers.zookeeper.password`: `--providers.zookeeper.password`:
KV Password KV Password

View file

@ -459,11 +459,14 @@ Expose containers by default. (Default: ```true```)
`TRAEFIK_PROVIDERS_CONSULCATALOG_NAMESPACE`: `TRAEFIK_PROVIDERS_CONSULCATALOG_NAMESPACE`:
Sets the namespace used to discover services (Consul Enterprise only). Sets the namespace used to discover services (Consul Enterprise only).
`TRAEFIK_PROVIDERS_CONSULCATALOG_NAMESPACES`:
Sets the namespaces used to discover services (Consul Enterprise only).
`TRAEFIK_PROVIDERS_CONSULCATALOG_PREFIX`: `TRAEFIK_PROVIDERS_CONSULCATALOG_PREFIX`:
Prefix for consul service tags. Default 'traefik' (Default: ```traefik```) Prefix for consul service tags. (Default: ```traefik```)
`TRAEFIK_PROVIDERS_CONSULCATALOG_REFRESHINTERVAL`: `TRAEFIK_PROVIDERS_CONSULCATALOG_REFRESHINTERVAL`:
Interval for check Consul API. Default 15s (Default: ```15```) Interval for check Consul API. (Default: ```15```)
`TRAEFIK_PROVIDERS_CONSULCATALOG_REQUIRECONSISTENT`: `TRAEFIK_PROVIDERS_CONSULCATALOG_REQUIRECONSISTENT`:
Forces the read to be fully consistent. (Default: ```false```) Forces the read to be fully consistent. (Default: ```false```)
@ -481,7 +484,10 @@ Watch Consul API events. (Default: ```false```)
KV store endpoints (Default: ```127.0.0.1:8500```) KV store endpoints (Default: ```127.0.0.1:8500```)
`TRAEFIK_PROVIDERS_CONSUL_NAMESPACE`: `TRAEFIK_PROVIDERS_CONSUL_NAMESPACE`:
KV Namespace Sets the namespace used to discover the configuration (Consul Enterprise only).
`TRAEFIK_PROVIDERS_CONSUL_NAMESPACES`:
Sets the namespaces used to discover the configuration (Consul Enterprise only).
`TRAEFIK_PROVIDERS_CONSUL_PASSWORD`: `TRAEFIK_PROVIDERS_CONSUL_PASSWORD`:
KV Password KV Password
@ -594,9 +600,6 @@ Enable Etcd backend with default settings. (Default: ```false```)
`TRAEFIK_PROVIDERS_ETCD_ENDPOINTS`: `TRAEFIK_PROVIDERS_ETCD_ENDPOINTS`:
KV store endpoints (Default: ```127.0.0.1:2379```) KV store endpoints (Default: ```127.0.0.1:2379```)
`TRAEFIK_PROVIDERS_ETCD_NAMESPACE`:
KV Namespace
`TRAEFIK_PROVIDERS_ETCD_PASSWORD`: `TRAEFIK_PROVIDERS_ETCD_PASSWORD`:
KV Password KV Password
@ -858,9 +861,6 @@ Enable Redis backend with default settings. (Default: ```false```)
`TRAEFIK_PROVIDERS_REDIS_ENDPOINTS`: `TRAEFIK_PROVIDERS_REDIS_ENDPOINTS`:
KV store endpoints (Default: ```127.0.0.1:6379```) KV store endpoints (Default: ```127.0.0.1:6379```)
`TRAEFIK_PROVIDERS_REDIS_NAMESPACE`:
KV Namespace
`TRAEFIK_PROVIDERS_REDIS_PASSWORD`: `TRAEFIK_PROVIDERS_REDIS_PASSWORD`:
KV Password KV Password
@ -900,9 +900,6 @@ Enable ZooKeeper backend with default settings. (Default: ```false```)
`TRAEFIK_PROVIDERS_ZOOKEEPER_ENDPOINTS`: `TRAEFIK_PROVIDERS_ZOOKEEPER_ENDPOINTS`:
KV store endpoints (Default: ```127.0.0.1:2181```) KV store endpoints (Default: ```127.0.0.1:2181```)
`TRAEFIK_PROVIDERS_ZOOKEEPER_NAMESPACE`:
KV Namespace
`TRAEFIK_PROVIDERS_ZOOKEEPER_PASSWORD`: `TRAEFIK_PROVIDERS_ZOOKEEPER_PASSWORD`:
KV Password KV Password

View file

@ -28,12 +28,6 @@
[entryPoints.EntryPoint0.forwardedHeaders] [entryPoints.EntryPoint0.forwardedHeaders]
insecure = true insecure = true
trustedIPs = ["foobar", "foobar"] trustedIPs = ["foobar", "foobar"]
[entryPoints.EntryPoint0.udp]
timeout = 42
[entryPoints.EntryPoint0.http2]
maxConcurrentStreams = 42
[entryPoints.EntryPoint0.http3]
advertisedPort = 42
[entryPoints.EntryPoint0.http] [entryPoints.EntryPoint0.http]
middlewares = ["foobar", "foobar"] middlewares = ["foobar", "foobar"]
[entryPoints.EntryPoint0.http.redirections] [entryPoints.EntryPoint0.http.redirections]
@ -53,6 +47,8 @@
[[entryPoints.EntryPoint0.http.tls.domains]] [[entryPoints.EntryPoint0.http.tls.domains]]
main = "foobar" main = "foobar"
sans = ["foobar", "foobar"] sans = ["foobar", "foobar"]
[entryPoints.EntryPoint0.http2]
maxConcurrentStreams = 42
[entryPoints.EntryPoint0.http3] [entryPoints.EntryPoint0.http3]
advertisedPort = 42 advertisedPort = 42
[entryPoints.EntryPoint0.udp] [entryPoints.EntryPoint0.udp]
@ -161,6 +157,7 @@
connectByDefault = true connectByDefault = true
serviceName = "foobar" serviceName = "foobar"
namespace = "foobar" namespace = "foobar"
namespaces = ["foobar", "foobar"]
watch = true watch = true
[providers.consulCatalog.endpoint] [providers.consulCatalog.endpoint]
address = "foobar" address = "foobar"
@ -194,6 +191,7 @@
password = "foobar" password = "foobar"
token = "foobar" token = "foobar"
namespace = "foobar" namespace = "foobar"
namespaces = ["foobar", "foobar"]
[providers.consul.tls] [providers.consul.tls]
ca = "foobar" ca = "foobar"
caOptional = true caOptional = true
@ -206,7 +204,6 @@
username = "foobar" username = "foobar"
password = "foobar" password = "foobar"
token = "foobar" token = "foobar"
namespace = "foobar"
[providers.etcd.tls] [providers.etcd.tls]
ca = "foobar" ca = "foobar"
caOptional = true caOptional = true
@ -219,7 +216,6 @@
username = "foobar" username = "foobar"
password = "foobar" password = "foobar"
token = "foobar" token = "foobar"
namespace = "foobar"
[providers.zooKeeper.tls] [providers.zooKeeper.tls]
ca = "foobar" ca = "foobar"
caOptional = true caOptional = true
@ -232,7 +228,6 @@
username = "foobar" username = "foobar"
password = "foobar" password = "foobar"
token = "foobar" token = "foobar"
namespace = "foobar"
[providers.redis.tls] [providers.redis.tls]
ca = "foobar" ca = "foobar"
caOptional = true caOptional = true

View file

@ -32,12 +32,6 @@ entryPoints:
trustedIPs: trustedIPs:
- foobar - foobar
- foobar - foobar
http2:
maxConcurrentStreams: 42
http3:
advertisedPort: 42
udp:
timeout: 42
http: http:
redirections: redirections:
entryPoint: entryPoint:
@ -60,6 +54,8 @@ entryPoints:
sans: sans:
- foobar - foobar
- foobar - foobar
http2:
maxConcurrentStreams: 42
http3: http3:
advertisedPort: 42 advertisedPort: 42
udp: udp:
@ -173,6 +169,9 @@ providers:
connectByDefault: true connectByDefault: true
serviceName: foobar serviceName: foobar
namespace: foobar namespace: foobar
namespaces:
- foobar
- foobar
watch: true watch: true
endpoint: endpoint:
address: foobar address: foobar
@ -210,6 +209,9 @@ providers:
password: foobar password: foobar
token: foobar token: foobar
namespace: foobar namespace: foobar
namespaces:
- foobar
- foobar
tls: tls:
ca: foobar ca: foobar
caOptional: true caOptional: true
@ -224,7 +226,6 @@ providers:
username: foobar username: foobar
password: foobar password: foobar
token: foobar token: foobar
namespace: foobar
tls: tls:
ca: foobar ca: foobar
caOptional: true caOptional: true
@ -239,7 +240,6 @@ providers:
username: foobar username: foobar
password: foobar password: foobar
token: foobar token: foobar
namespace: foobar
tls: tls:
ca: foobar ca: foobar
caOptional: true caOptional: true
@ -254,7 +254,6 @@ providers:
username: foobar username: foobar
password: foobar password: foobar
token: foobar token: foobar
namespace: foobar
tls: tls:
ca: foobar ca: foobar
caOptional: true caOptional: true

View file

@ -183,10 +183,10 @@ type Providers struct {
KubernetesGateway *gateway.Provider `description:"Enable Kubernetes gateway api provider with default settings." json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` KubernetesGateway *gateway.Provider `description:"Enable Kubernetes gateway api provider with default settings." json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
Rest *rest.Provider `description:"Enable Rest backend with default settings." json:"rest,omitempty" toml:"rest,omitempty" yaml:"rest,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` Rest *rest.Provider `description:"Enable Rest backend with default settings." json:"rest,omitempty" toml:"rest,omitempty" yaml:"rest,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
Rancher *rancher.Provider `description:"Enable Rancher backend with default settings." json:"rancher,omitempty" toml:"rancher,omitempty" yaml:"rancher,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` Rancher *rancher.Provider `description:"Enable Rancher backend with default settings." json:"rancher,omitempty" toml:"rancher,omitempty" yaml:"rancher,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
ConsulCatalog *consulcatalog.Provider `description:"Enable ConsulCatalog backend with default settings." json:"consulCatalog,omitempty" toml:"consulCatalog,omitempty" yaml:"consulCatalog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` ConsulCatalog *consulcatalog.ProviderBuilder `description:"Enable ConsulCatalog backend with default settings." json:"consulCatalog,omitempty" toml:"consulCatalog,omitempty" yaml:"consulCatalog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
Ecs *ecs.Provider `description:"Enable AWS ECS backend with default settings." json:"ecs,omitempty" toml:"ecs,omitempty" yaml:"ecs,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` Ecs *ecs.Provider `description:"Enable AWS ECS backend with default settings." json:"ecs,omitempty" toml:"ecs,omitempty" yaml:"ecs,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
Consul *consul.Provider `description:"Enable Consul backend with default settings." json:"consul,omitempty" toml:"consul,omitempty" yaml:"consul,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` Consul *consul.ProviderBuilder `description:"Enable Consul backend with default settings." json:"consul,omitempty" toml:"consul,omitempty" yaml:"consul,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
Etcd *etcd.Provider `description:"Enable Etcd backend with default settings." json:"etcd,omitempty" toml:"etcd,omitempty" yaml:"etcd,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` Etcd *etcd.Provider `description:"Enable Etcd backend with default settings." json:"etcd,omitempty" toml:"etcd,omitempty" yaml:"etcd,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
ZooKeeper *zk.Provider `description:"Enable ZooKeeper backend with default settings." json:"zooKeeper,omitempty" toml:"zooKeeper,omitempty" yaml:"zooKeeper,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` ZooKeeper *zk.Provider `description:"Enable ZooKeeper backend with default settings." json:"zooKeeper,omitempty" toml:"zooKeeper,omitempty" yaml:"zooKeeper,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
Redis *redis.Provider `description:"Enable Redis backend with default settings." json:"redis,omitempty" toml:"redis,omitempty" yaml:"redis,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` Redis *redis.Provider `description:"Enable Redis backend with default settings." json:"redis,omitempty" toml:"redis,omitempty" yaml:"redis,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
@ -257,7 +257,7 @@ func (c *Configuration) SetEffectiveConfiguration() {
c.Pilot.SetDefaults() c.Pilot.SetDefaults()
} }
// Disable Gateway API provider if not enabled in experimental // Disable Gateway API provider if not enabled in experimental.
if c.Experimental == nil || !c.Experimental.KubernetesGateway { if c.Experimental == nil || !c.Experimental.KubernetesGateway {
c.Providers.KubernetesGateway = nil c.Providers.KubernetesGateway = nil
} }
@ -328,6 +328,14 @@ func (c *Configuration) ValidateConfiguration() error {
acmeEmail = resolver.ACME.Email acmeEmail = resolver.ACME.Email
} }
if c.Providers.ConsulCatalog != nil && c.Providers.ConsulCatalog.Namespace != "" && len(c.Providers.ConsulCatalog.Namespaces) > 0 {
return fmt.Errorf("consul catalog provider cannot have both namespace and namespaces options configured")
}
if c.Providers.Consul != nil && c.Providers.Consul.Namespace != "" && len(c.Providers.Consul.Namespaces) > 0 {
return fmt.Errorf("consul provider cannot have both namespace and namespaces options configured")
}
return nil return nil
} }

View file

@ -109,11 +109,15 @@ func NewProviderAggregator(conf static.Providers) ProviderAggregator {
} }
if conf.ConsulCatalog != nil { if conf.ConsulCatalog != nil {
p.quietAddProvider(conf.ConsulCatalog) for _, pvd := range conf.ConsulCatalog.BuildProviders() {
p.quietAddProvider(pvd)
}
} }
if conf.Consul != nil { if conf.Consul != nil {
p.quietAddProvider(conf.Consul) for _, pvd := range conf.Consul.BuildProviders() {
p.quietAddProvider(pvd)
}
} }
if conf.Etcd != nil { if conf.Etcd != nil {

View file

@ -219,7 +219,7 @@ func TestDefaultRule(t *testing.T) {
Status: api.HealthPassing, Status: api.HealthPassing,
}, },
}, },
defaultRule: DefaultTemplateRule, defaultRule: defaultTemplateRule,
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{ TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{}, Routers: map[string]*dynamic.TCPRouter{},
@ -262,8 +262,10 @@ func TestDefaultRule(t *testing.T) {
t.Parallel() t.Parallel()
p := Provider{ p := Provider{
Configuration: Configuration{
ExposedByDefault: true, ExposedByDefault: true,
DefaultRule: test.defaultRule, DefaultRule: test.defaultRule,
},
} }
err := p.Init() err := p.Init()
@ -2618,10 +2620,12 @@ func Test_buildConfiguration(t *testing.T) {
t.Parallel() t.Parallel()
p := Provider{ p := Provider{
Configuration: Configuration{
ExposedByDefault: true, ExposedByDefault: true,
DefaultRule: "Host(`{{ normalize .Name }}.traefik.wtf`)", DefaultRule: "Host(`{{ normalize .Name }}.traefik.wtf`)",
ConnectAware: test.ConnectAware, ConnectAware: test.ConnectAware,
Constraints: test.constraints, Constraints: test.constraints,
},
} }
err := p.Init() err := p.Init()
@ -2651,3 +2655,55 @@ func Test_buildConfiguration(t *testing.T) {
}) })
} }
} }
func TestNamespaces(t *testing.T) {
testCases := []struct {
desc string
namespace string
namespaces []string
expectedNamespaces []string
}{
{
desc: "no defined namespaces",
expectedNamespaces: []string{""},
},
{
desc: "deprecated: use of defined namespace",
namespace: "test-ns",
expectedNamespaces: []string{"test-ns"},
},
{
desc: "use of 1 defined namespaces",
namespaces: []string{"test-ns"},
expectedNamespaces: []string{"test-ns"},
},
{
desc: "use of multiple defined namespaces",
namespaces: []string{"test-ns1", "test-ns2", "test-ns3", "test-ns4"},
expectedNamespaces: []string{"test-ns1", "test-ns2", "test-ns3", "test-ns4"},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
pb := &ProviderBuilder{
Namespace: test.namespace,
Namespaces: test.namespaces,
}
assert.Equal(t, test.expectedNamespaces, extractNSFromProvider(pb.BuildProviders()))
})
}
}
func extractNSFromProvider(providers []*Provider) []string {
res := make([]string, len(providers))
for i, p := range providers {
res[i] = p.namespace
}
return res
}

View file

@ -22,8 +22,11 @@ import (
"github.com/traefik/traefik/v2/pkg/types" "github.com/traefik/traefik/v2/pkg/types"
) )
// DefaultTemplateRule The default template for the default rule. // defaultTemplateRule is the default template for the default rule.
const DefaultTemplateRule = "Host(`{{ normalize .Name }}`)" const defaultTemplateRule = "Host(`{{ normalize .Name }}`)"
// providerName is the Consul Catalog provider name.
const providerName = "consulcatalog"
var _ provider.Provider = (*Provider)(nil) var _ provider.Provider = (*Provider)(nil)
@ -41,12 +44,50 @@ type itemData struct {
ExtraConf configuration ExtraConf configuration
} }
// Provider holds configurations of the provider. // ProviderBuilder is responsible for constructing namespaced instances of the Consul Catalog provider.
type Provider struct { type ProviderBuilder struct {
Configuration `export:"true"`
// Deprecated: use Namespaces option instead.
Namespace string `description:"Sets the namespace used to discover services (Consul Enterprise only)." json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
Namespaces []string `description:"Sets the namespaces used to discover services (Consul Enterprise only)." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty"`
}
// BuildProviders builds Consul Catalog provider instances for the given namespaces configuration.
func (p *ProviderBuilder) BuildProviders() []*Provider {
// We can warn about that, because we've already made sure before that
// Namespace and Namespaces are mutually exclusive.
if p.Namespace != "" {
log.WithoutContext().Warnf("Namespace option is deprecated, please use the Namespaces option instead.")
}
if len(p.Namespaces) == 0 {
return []*Provider{{
Configuration: p.Configuration,
name: providerName,
// p.Namespace could very well be empty.
namespace: p.Namespace,
}}
}
var providers []*Provider
for _, namespace := range p.Namespaces {
providers = append(providers, &Provider{
Configuration: p.Configuration,
name: providerName + "-" + namespace,
namespace: namespace,
})
}
return providers
}
// Configuration represents the Consul Catalog provider configuration.
type Configuration struct {
Constraints string `description:"Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"` Constraints string `description:"Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
Endpoint *EndpointConfig `description:"Consul endpoint settings" json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"` Endpoint *EndpointConfig `description:"Consul endpoint settings" json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"`
Prefix string `description:"Prefix for consul service tags. Default 'traefik'" json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"` Prefix string `description:"Prefix for consul service tags." json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"`
RefreshInterval ptypes.Duration `description:"Interval for check Consul API. Default 15s" json:"refreshInterval,omitempty" toml:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty" export:"true"` RefreshInterval ptypes.Duration `description:"Interval for check Consul API." json:"refreshInterval,omitempty" toml:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty" export:"true"`
RequireConsistent bool `description:"Forces the read to be fully consistent." json:"requireConsistent,omitempty" toml:"requireConsistent,omitempty" yaml:"requireConsistent,omitempty" export:"true"` RequireConsistent bool `description:"Forces the read to be fully consistent." json:"requireConsistent,omitempty" toml:"requireConsistent,omitempty" yaml:"requireConsistent,omitempty" export:"true"`
Stale bool `description:"Use stale consistency for catalog reads." json:"stale,omitempty" toml:"stale,omitempty" yaml:"stale,omitempty" export:"true"` Stale bool `description:"Use stale consistency for catalog reads." json:"stale,omitempty" toml:"stale,omitempty" yaml:"stale,omitempty" export:"true"`
Cache bool `description:"Use local agent caching for catalog reads." json:"cache,omitempty" toml:"cache,omitempty" yaml:"cache,omitempty" export:"true"` Cache bool `description:"Use local agent caching for catalog reads." json:"cache,omitempty" toml:"cache,omitempty" yaml:"cache,omitempty" export:"true"`
@ -55,9 +96,25 @@ type Provider struct {
ConnectAware bool `description:"Enable Consul Connect support." json:"connectAware,omitempty" toml:"connectAware,omitempty" yaml:"connectAware,omitempty" export:"true"` ConnectAware bool `description:"Enable Consul Connect support." json:"connectAware,omitempty" toml:"connectAware,omitempty" yaml:"connectAware,omitempty" export:"true"`
ConnectByDefault bool `description:"Consider every service as Connect capable by default." json:"connectByDefault,omitempty" toml:"connectByDefault,omitempty" yaml:"connectByDefault,omitempty" export:"true"` ConnectByDefault bool `description:"Consider every service as Connect capable by default." json:"connectByDefault,omitempty" toml:"connectByDefault,omitempty" yaml:"connectByDefault,omitempty" export:"true"`
ServiceName string `description:"Name of the Traefik service in Consul Catalog (needs to be registered via the orchestrator or manually)." json:"serviceName,omitempty" toml:"serviceName,omitempty" yaml:"serviceName,omitempty" export:"true"` ServiceName string `description:"Name of the Traefik service in Consul Catalog (needs to be registered via the orchestrator or manually)." json:"serviceName,omitempty" toml:"serviceName,omitempty" yaml:"serviceName,omitempty" export:"true"`
Namespace string `description:"Sets the namespace used to discover services (Consul Enterprise only)." json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty" export:"true"`
Watch bool `description:"Watch Consul API events." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"` Watch bool `description:"Watch Consul API events." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"`
}
// SetDefaults sets the default values.
func (c *Configuration) SetDefaults() {
c.Endpoint = &EndpointConfig{}
c.RefreshInterval = ptypes.Duration(15 * time.Second)
c.Prefix = "traefik"
c.ExposedByDefault = true
c.DefaultRule = defaultTemplateRule
c.ServiceName = "traefik"
}
// Provider is the Consul Catalog provider implementation.
type Provider struct {
Configuration
name string
namespace string
client *api.Client client *api.Client
defaultRuleTpl *template.Template defaultRuleTpl *template.Template
certChan chan *connectCert certChan chan *connectCert
@ -81,17 +138,6 @@ type EndpointHTTPAuthConfig struct {
Password string `description:"Basic Auth password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"` Password string `description:"Basic Auth password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"`
} }
// SetDefaults sets the default values.
func (p *Provider) SetDefaults() {
endpoint := &EndpointConfig{}
p.Endpoint = endpoint
p.RefreshInterval = ptypes.Duration(15 * time.Second)
p.Prefix = "traefik"
p.ExposedByDefault = true
p.DefaultRule = DefaultTemplateRule
p.ServiceName = "traefik"
}
// Init the provider. // Init the provider.
func (p *Provider) Init() error { func (p *Provider) Init() error {
defaultRuleTpl, err := provider.MakeDefaultRuleTemplate(p.DefaultRule, nil) defaultRuleTpl, err := provider.MakeDefaultRuleTemplate(p.DefaultRule, nil)
@ -103,19 +149,24 @@ func (p *Provider) Init() error {
p.certChan = make(chan *connectCert, 1) p.certChan = make(chan *connectCert, 1)
p.watchServicesChan = make(chan struct{}, 1) p.watchServicesChan = make(chan struct{}, 1)
// In case they didn't initialize Provider with BuildProviders.
if p.name == "" {
p.name = providerName
}
return nil return nil
} }
// Provide allows the consul catalog provider to provide configurations to traefik using the given configuration channel. // Provide allows the consul catalog provider to provide configurations to traefik using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error { func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
var err error var err error
p.client, err = createClient(p.Namespace, p.Endpoint) p.client, err = createClient(p.namespace, p.Endpoint)
if err != nil { if err != nil {
return fmt.Errorf("failed to create consul client: %w", err) return fmt.Errorf("failed to create consul client: %w", err)
} }
pool.GoCtx(func(routineCtx context.Context) { pool.GoCtx(func(routineCtx context.Context) {
ctxLog := log.With(routineCtx, log.Str(log.ProviderName, "consulcatalog")) ctxLog := log.With(routineCtx, log.Str(log.ProviderName, p.name))
logger := log.FromContext(ctxLog) logger := log.FromContext(ctxLog)
operation := func() error { operation := func() error {
@ -210,7 +261,7 @@ func (p *Provider) loadConfiguration(ctx context.Context, certInfo *connectCert,
} }
configurationChan <- dynamic.Message{ configurationChan <- dynamic.Message{
ProviderName: "consulcatalog", ProviderName: p.name,
Configuration: p.buildConfiguration(ctx, data, certInfo), Configuration: p.buildConfiguration(ctx, data, certInfo),
} }

View file

@ -4,30 +4,80 @@ import (
"errors" "errors"
"github.com/kvtools/valkeyrie/store" "github.com/kvtools/valkeyrie/store"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/provider" "github.com/traefik/traefik/v2/pkg/provider"
"github.com/traefik/traefik/v2/pkg/provider/kv" "github.com/traefik/traefik/v2/pkg/provider/kv"
) )
// providerName is the Consul provider name.
const providerName = "consul"
var _ provider.Provider = (*Provider)(nil) var _ provider.Provider = (*Provider)(nil)
// Provider holds configurations of the provider. // ProviderBuilder is responsible for constructing namespaced instances of the Consul provider.
type Provider struct { type ProviderBuilder struct {
kv.Provider `export:"true"` kv.Provider `export:"true"`
// Deprecated: use Namespaces instead.
Namespace string `description:"Sets the namespace used to discover the configuration (Consul Enterprise only)." json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
Namespaces []string `description:"Sets the namespaces used to discover the configuration (Consul Enterprise only)." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty"`
} }
// SetDefaults sets the default values. // SetDefaults sets the default values.
func (p *Provider) SetDefaults() { func (p *ProviderBuilder) SetDefaults() {
p.Provider.SetDefaults() p.Provider.SetDefaults()
p.Endpoints = []string{"127.0.0.1:8500"} p.Endpoints = []string{"127.0.0.1:8500"}
} }
// BuildProviders builds Consul provider instances for the given namespaces configuration.
func (p *ProviderBuilder) BuildProviders() []*Provider {
// We can warn about that, because we've already made sure before that
// Namespace and Namespaces are mutually exclusive.
if p.Namespace != "" {
log.WithoutContext().Warnf("Namespace option is deprecated, please use the Namespaces option instead.")
}
if len(p.Namespaces) == 0 {
return []*Provider{{
Provider: p.Provider,
name: providerName,
// p.Namespace could very well be empty.
namespace: p.Namespace,
}}
}
var providers []*Provider
for _, namespace := range p.Namespaces {
providers = append(providers, &Provider{
Provider: p.Provider,
name: providerName + "-" + namespace,
namespace: namespace,
})
}
return providers
}
// Provider holds configurations of the provider.
type Provider struct {
kv.Provider
name string
namespace string
}
// Init the provider. // Init the provider.
func (p *Provider) Init() error { func (p *Provider) Init() error {
// Wildcard namespace allows fetching KV values from any namespace for recursive requests (see https://www.consul.io/api/kv#ns). // Wildcard namespace allows fetching KV values from any namespace for recursive requests (see https://www.consul.io/api/kv#ns).
// As we are not supporting multiple namespaces at the same time, wildcard namespace is not allowed. // As we are not supporting multiple namespaces at the same time, wildcard namespace is not allowed.
if p.Namespace == "*" { if p.namespace == "*" {
return errors.New("wildcard namespace is not supported") return errors.New("wildcard namespace is not supported")
} }
return p.Provider.Init(store.CONSUL, "consul") // In case they didn't initialize with BuildProviders.
if p.name == "" {
p.name = providerName
}
return p.Provider.Init(store.CONSUL, p.name, p.namespace)
} }

View file

@ -0,0 +1,59 @@
package consul
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNamespaces(t *testing.T) {
testCases := []struct {
desc string
namespace string
namespaces []string
expectedNamespaces []string
}{
{
desc: "no defined namespaces",
expectedNamespaces: []string{""},
},
{
desc: "deprecated: use of defined namespace",
namespace: "test-ns",
expectedNamespaces: []string{"test-ns"},
},
{
desc: "use of 1 defined namespaces",
namespaces: []string{"test-ns"},
expectedNamespaces: []string{"test-ns"},
},
{
desc: "use of multiple defined namespaces",
namespaces: []string{"test-ns1", "test-ns2", "test-ns3", "test-ns4"},
expectedNamespaces: []string{"test-ns1", "test-ns2", "test-ns3", "test-ns4"},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
pb := &ProviderBuilder{
Namespace: test.namespace,
Namespaces: test.namespaces,
}
assert.Equal(t, test.expectedNamespaces, extractNSFromProvider(pb.BuildProviders()))
})
}
}
func extractNSFromProvider(providers []*Provider) []string {
res := make([]string, len(providers))
for i, p := range providers {
res[i] = p.namespace
}
return res
}

View file

@ -21,5 +21,5 @@ func (p *Provider) SetDefaults() {
// Init the provider. // Init the provider.
func (p *Provider) Init() error { func (p *Provider) Init() error {
return p.Provider.Init(store.ETCDV3, "etcd") return p.Provider.Init(store.ETCDV3, "etcd", "")
} }

View file

@ -30,12 +30,12 @@ type Provider struct {
Username string `description:"KV Username" json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty" loggable:"false"` Username string `description:"KV Username" json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty" loggable:"false"`
Password string `description:"KV Password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"` Password string `description:"KV Password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"`
Token string `description:"KV Token" json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"` Token string `description:"KV Token" json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
Namespace string `description:"KV Namespace" json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
TLS *types.ClientTLS `description:"Enable TLS support" json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true" ` TLS *types.ClientTLS `description:"Enable TLS support" json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true" `
name string
namespace string
storeType store.Backend storeType store.Backend
kvClient store.Store kvClient store.Store
name string
} }
// SetDefaults sets the default values. // SetDefaults sets the default values.
@ -44,11 +44,12 @@ func (p *Provider) SetDefaults() {
} }
// Init the provider. // Init the provider.
func (p *Provider) Init(storeType store.Backend, name string) error { func (p *Provider) Init(storeType store.Backend, name, namespace string) error {
ctx := log.With(context.Background(), log.Str(log.ProviderName, name)) ctx := log.With(context.Background(), log.Str(log.ProviderName, name))
p.storeType = storeType
p.name = name p.name = name
p.namespace = namespace
p.storeType = storeType
kvClient, err := p.createKVClient(ctx) kvClient, err := p.createKVClient(ctx)
if err != nil { if err != nil {
@ -167,7 +168,7 @@ func (p *Provider) createKVClient(ctx context.Context) (store.Store, error) {
Username: p.Username, Username: p.Username,
Password: p.Password, Password: p.Password,
Token: p.Token, Token: p.Token,
Namespace: p.Namespace, Namespace: p.namespace,
} }
if p.TLS != nil { if p.TLS != nil {

View file

@ -21,5 +21,5 @@ func (p *Provider) SetDefaults() {
// Init the provider. // Init the provider.
func (p *Provider) Init() error { func (p *Provider) Init() error {
return p.Provider.Init(store.REDIS, "redis") return p.Provider.Init(store.REDIS, "redis", "")
} }

View file

@ -21,5 +21,5 @@ func (p *Provider) SetDefaults() {
// Init the provider. // Init the provider.
func (p *Provider) Init() error { func (p *Provider) Init() error {
return p.Provider.Init(store.ZK, "zookeeper") return p.Provider.Init(store.ZK, "zookeeper", "")
} }

View file

@ -682,7 +682,8 @@ func TestDo_staticConfiguration(t *testing.T) {
Prefix: "MyPrefix", Prefix: "MyPrefix",
} }
config.Providers.ConsulCatalog = &consulcatalog.Provider{ config.Providers.ConsulCatalog = &consulcatalog.ProviderBuilder{
Configuration: consulcatalog.Configuration{
Constraints: `Label("foo", "bar")`, Constraints: `Label("foo", "bar")`,
Endpoint: &consulcatalog.EndpointConfig{ Endpoint: &consulcatalog.EndpointConfig{
Address: "MyAddress", Address: "MyAddress",
@ -709,6 +710,9 @@ func TestDo_staticConfiguration(t *testing.T) {
Cache: true, Cache: true,
ExposedByDefault: true, ExposedByDefault: true,
DefaultRule: "PathPrefix(`/`)", DefaultRule: "PathPrefix(`/`)",
},
Namespace: "ns",
Namespaces: []string{"ns1", "ns2"},
} }
config.Providers.Ecs = &ecs.Provider{ config.Providers.Ecs = &ecs.Provider{
@ -723,7 +727,7 @@ func TestDo_staticConfiguration(t *testing.T) {
SecretAccessKey: "AwsSecretAccessKey", SecretAccessKey: "AwsSecretAccessKey",
} }
config.Providers.Consul = &consul.Provider{ config.Providers.Consul = &consul.ProviderBuilder{
Provider: kv.Provider{ Provider: kv.Provider{
RootKey: "RootKey", RootKey: "RootKey",
Endpoints: nil, Endpoints: nil,
@ -737,6 +741,8 @@ func TestDo_staticConfiguration(t *testing.T) {
InsecureSkipVerify: true, InsecureSkipVerify: true,
}, },
}, },
Namespace: "ns",
Namespaces: []string{"ns1", "ns2"},
} }
config.Providers.Etcd = &etcd.Provider{ config.Providers.Etcd = &etcd.Provider{

View file

@ -206,7 +206,12 @@
"stale": true, "stale": true,
"cache": true, "cache": true,
"exposedByDefault": true, "exposedByDefault": true,
"defaultRule": "xxxx" "defaultRule": "xxxx",
"namespace": "xxxx",
"namespaces": [
"xxxx",
"xxxx"
]
}, },
"ecs": { "ecs": {
"constraints": "Label(\"foo\", \"bar\")", "constraints": "Label(\"foo\", \"bar\")",
@ -232,7 +237,12 @@
"cert": "xxxx", "cert": "xxxx",
"key": "xxxx", "key": "xxxx",
"insecureSkipVerify": true "insecureSkipVerify": true
} },
"namespace": "xxxx",
"namespaces": [
"xxxx",
"xxxx"
]
}, },
"etcd": { "etcd": {
"rootKey": "xxxx", "rootKey": "xxxx",

View file

@ -1142,9 +1142,15 @@ export default {
getProviderLogoPath (provider) { getProviderLogoPath (provider) {
const name = provider.toLowerCase() const name = provider.toLowerCase()
if (name.includes('plugin-')) { if (name.startsWith('plugin-')) {
return 'statics/providers/plugin.svg' return 'statics/providers/plugin.svg'
} }
if (name.startsWith('consul-')) {
return `statics/providers/consul.svg`
}
if (name.startsWith('consulcatalog-')) {
return `statics/providers/consulcatalog.svg`
}
return `statics/providers/${name}.svg` return `statics/providers/${name}.svg`
} }

View file

@ -66,9 +66,15 @@ export default {
const provider = this.getProvider(service) const provider = this.getProvider(service)
const name = provider.toLowerCase() const name = provider.toLowerCase()
if (name.includes('plugin-')) { if (name.startsWith('plugin-')) {
return 'statics/providers/plugin.svg' return 'statics/providers/plugin.svg'
} }
if (name.startsWith('consul-')) {
return `statics/providers/consul.svg`
}
if (name.startsWith('consulcatalog-')) {
return `statics/providers/consulcatalog.svg`
}
return `statics/providers/${name}.svg` return `statics/providers/${name}.svg`
} }

View file

@ -132,9 +132,15 @@ export default {
getProviderLogoPath () { getProviderLogoPath () {
const name = this.data.provider.toLowerCase() const name = this.data.provider.toLowerCase()
if (name.includes('plugin-')) { if (name.startsWith('plugin-')) {
return 'statics/providers/plugin.svg' return 'statics/providers/plugin.svg'
} }
if (name.startsWith('consul-')) {
return `statics/providers/consul.svg`
}
if (name.startsWith('consulcatalog-')) {
return `statics/providers/consulcatalog.svg`
}
return `statics/providers/${name}.svg` return `statics/providers/${name}.svg`
} }

View file

@ -146,9 +146,15 @@ export default {
getProviderLogoPath () { getProviderLogoPath () {
const name = this.data.provider.toLowerCase() const name = this.data.provider.toLowerCase()
if (name.includes('plugin-')) { if (name.startsWith('plugin-')) {
return 'statics/providers/plugin.svg' return 'statics/providers/plugin.svg'
} }
if (name.startsWith('consul-')) {
return `statics/providers/consul.svg`
}
if (name.startsWith('consulcatalog-')) {
return `statics/providers/consulcatalog.svg`
}
return `statics/providers/${name}.svg` return `statics/providers/${name}.svg`
} }

View file

@ -66,9 +66,15 @@ export default {
const provider = this.getProvider(service) const provider = this.getProvider(service)
const name = provider.toLowerCase() const name = provider.toLowerCase()
if (name.includes('plugin-')) { if (name.startsWith('plugin-')) {
return 'statics/providers/plugin.svg' return 'statics/providers/plugin.svg'
} }
if (name.startsWith('consul-')) {
return `statics/providers/consul.svg`
}
if (name.startsWith('consulcatalog-')) {
return `statics/providers/consulcatalog.svg`
}
return `statics/providers/${name}.svg` return `statics/providers/${name}.svg`
} }

View file

@ -11,9 +11,15 @@ export default {
getLogoPath () { getLogoPath () {
const name = this.name.toLowerCase() const name = this.name.toLowerCase()
if (name.includes('plugin-')) { if (name.startsWith('plugin-')) {
return 'statics/providers/plugin.svg' return 'statics/providers/plugin.svg'
} }
if (name.startsWith('consul-')) {
return `statics/providers/consul.svg`
}
if (name.startsWith('consulcatalog-')) {
return `statics/providers/consulcatalog.svg`
}
return `statics/providers/${name}.svg` return `statics/providers/${name}.svg`
} }

View file

@ -28,9 +28,15 @@ export default {
getLogoPath () { getLogoPath () {
const name = this.getName.toLowerCase() const name = this.getName.toLowerCase()
if (name.includes('plugin-')) { if (name.startsWith('plugin-')) {
return 'statics/providers/plugin.svg' return 'statics/providers/plugin.svg'
} }
if (name.startsWith('consul-')) {
return `statics/providers/consul.svg`
}
if (name.startsWith('consulcatalog-')) {
return `statics/providers/consulcatalog.svg`
}
return `statics/providers/${name}.svg` return `statics/providers/${name}.svg`
} }