Support multiple namespaces in the Nomad Provider
This commit is contained in:
parent
358f47443e
commit
f7be1e97df
22 changed files with 266 additions and 60 deletions
|
@ -142,6 +142,7 @@ issues:
|
||||||
- 'SA1019: cfg.FeaturePolicy is deprecated'
|
- 'SA1019: cfg.FeaturePolicy is deprecated'
|
||||||
- 'SA1019: c.Providers.ConsulCatalog.Namespace is deprecated'
|
- 'SA1019: c.Providers.ConsulCatalog.Namespace is deprecated'
|
||||||
- 'SA1019: c.Providers.Consul.Namespace is deprecated'
|
- 'SA1019: c.Providers.Consul.Namespace is deprecated'
|
||||||
|
- 'SA1019: c.Providers.Nomad.Namespace is deprecated'
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
- path: '(.+)_test.go'
|
- path: '(.+)_test.go'
|
||||||
linters:
|
linters:
|
||||||
|
|
|
@ -7,6 +7,7 @@ This page is maintained and updated periodically to reflect our roadmap and any
|
||||||
| [Pilot](#pilot) | 2.7 | 2.8 | 2.9 |
|
| [Pilot](#pilot) | 2.7 | 2.8 | 2.9 |
|
||||||
| [Consul Enterprise Namespace](#consul-enterprise-namespace) | 2.8 | N/A | 3.0 |
|
| [Consul Enterprise Namespace](#consul-enterprise-namespace) | 2.8 | N/A | 3.0 |
|
||||||
| [TLS 1.0 and 1.1 Support](#tls-10-and-11) | N/A | 2.8 | N/A |
|
| [TLS 1.0 and 1.1 Support](#tls-10-and-11) | N/A | 2.8 | N/A |
|
||||||
|
| [Nomad Namespace](#nomad-namespace) | 2.10 | N/A | 3.0 |
|
||||||
| [Kubernetes CRDs API Group `traefik.containo.us`](#kubernetes-crds-api-group-traefikcontainous) | 2.10 | N/A | 3.0 |
|
| [Kubernetes CRDs API Group `traefik.containo.us`](#kubernetes-crds-api-group-traefikcontainous) | 2.10 | N/A | 3.0 |
|
||||||
| [Kubernetes CRDs API Version `traefik.io/v1alpha1`](#kubernetes-crds-api-version-traefikiov1alpha1) | N/A | N/A | 3.0 |
|
| [Kubernetes CRDs API Version `traefik.io/v1alpha1`](#kubernetes-crds-api-version-traefikiov1alpha1) | N/A | N/A | 3.0 |
|
||||||
|
|
||||||
|
@ -29,6 +30,11 @@ please use the `namespaces` options instead.
|
||||||
|
|
||||||
Starting on 2.8 the default TLS options will use the minimum version of TLS 1.2. Of course, it can still be overridden with custom configuration.
|
Starting on 2.8 the default TLS options will use the minimum version of TLS 1.2. Of course, it can still be overridden with custom configuration.
|
||||||
|
|
||||||
|
### Nomad Namespace
|
||||||
|
|
||||||
|
Starting on 2.10 the `namespace` option of the Nomad provider is deprecated,
|
||||||
|
please use the `namespaces` options instead.
|
||||||
|
|
||||||
### Kubernetes CRDs API Group `traefik.containo.us`
|
### Kubernetes CRDs API Group `traefik.containo.us`
|
||||||
|
|
||||||
In v2.10, the Kubernetes CRDs API Group `traefik.containo.us` is deprecated, and its support will end starting with Traefik v3. Please use the API Group `traefik.io` instead.
|
In v2.10, the Kubernetes CRDs API Group `traefik.containo.us` is deprecated, and its support will end starting with Traefik v3. Please use the API Group `traefik.io` instead.
|
||||||
|
|
|
@ -499,6 +499,12 @@ In `v2.9`, Traefik Pilot support has been removed.
|
||||||
|
|
||||||
## v2.10
|
## v2.10
|
||||||
|
|
||||||
|
### Nomad Namespace
|
||||||
|
|
||||||
|
In `v2.10`, the `namespace` option of the Nomad provider is deprecated, please use the `namespaces` options instead.
|
||||||
|
|
||||||
|
## v2.10
|
||||||
|
|
||||||
### Kubernetes CRDs
|
### Kubernetes CRDs
|
||||||
|
|
||||||
In `v2.10`, the Kubernetes CRDs API Group `traefik.containo.us` is deprecated, and its support will end starting with Traefik v3. Please use the API Group `traefik.io` instead.
|
In `v2.10`, the Kubernetes CRDs API Group `traefik.containo.us` is deprecated, and its support will end starting with Traefik v3. Please use the API Group `traefik.io` instead.
|
||||||
|
|
|
@ -442,24 +442,65 @@ For additional information, refer to [Restrict the Scope of Service Discovery](.
|
||||||
|
|
||||||
### `namespace`
|
### `namespace`
|
||||||
|
|
||||||
|
??? warning "Deprecated in favor of the [`namespaces`](#namespaces) option."
|
||||||
|
|
||||||
|
_Optional, Default=""_
|
||||||
|
|
||||||
|
The `namespace` option defines the namespace in which the Nomad services will be discovered.
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
|
||||||
|
One should only define either the `namespaces` option or the `namespace` option.
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
providers:
|
||||||
|
nomad:
|
||||||
|
namespace: "production"
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[providers.nomad]
|
||||||
|
namespace = "production"
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--providers.nomad.namespace=production
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### `namespaces`
|
||||||
|
|
||||||
_Optional, Default=""_
|
_Optional, Default=""_
|
||||||
|
|
||||||
The `namespace` option defines the namespace in which the Nomad services will be discovered.
|
The `namespaces` option defines the namespaces in which the nomad services will be discovered.
|
||||||
|
When using the `namespaces` option, the discovered object names will be suffixed as shown below:
|
||||||
|
|
||||||
|
```text
|
||||||
|
<resource-name>@nomad-<namespace>
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
|
||||||
|
One should only define either the `namespaces` option or the `namespace` option.
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
```yaml tab="File (YAML)"
|
||||||
providers:
|
providers:
|
||||||
nomad:
|
nomad:
|
||||||
namespace: "production"
|
namespaces:
|
||||||
|
- "ns1"
|
||||||
|
- "ns2"
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
```toml tab="File (TOML)"
|
||||||
[providers.nomad]
|
[providers.nomad]
|
||||||
namespace = "production"
|
namespaces = ["ns1", "ns2"]
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash tab="CLI"
|
```bash tab="CLI"
|
||||||
--providers.nomad.namespace=production
|
--providers.nomad.namespaces=ns1,ns2
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
|
@ -858,6 +858,9 @@ Expose Nomad services by default. (Default: ```true```)
|
||||||
`--providers.nomad.namespace`:
|
`--providers.nomad.namespace`:
|
||||||
Sets the Nomad namespace used to discover services.
|
Sets the Nomad namespace used to discover services.
|
||||||
|
|
||||||
|
`--providers.nomad.namespaces`:
|
||||||
|
Sets the Nomad namespaces used to discover services.
|
||||||
|
|
||||||
`--providers.nomad.prefix`:
|
`--providers.nomad.prefix`:
|
||||||
Prefix for nomad service tags. (Default: ```traefik```)
|
Prefix for nomad service tags. (Default: ```traefik```)
|
||||||
|
|
||||||
|
|
|
@ -858,6 +858,9 @@ Expose Nomad services by default. (Default: ```true```)
|
||||||
`TRAEFIK_PROVIDERS_NOMAD_NAMESPACE`:
|
`TRAEFIK_PROVIDERS_NOMAD_NAMESPACE`:
|
||||||
Sets the Nomad namespace used to discover services.
|
Sets the Nomad namespace used to discover services.
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_NOMAD_NAMESPACES`:
|
||||||
|
Sets the Nomad namespaces used to discover services.
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_NOMAD_PREFIX`:
|
`TRAEFIK_PROVIDERS_NOMAD_PREFIX`:
|
||||||
Prefix for nomad service tags. (Default: ```traefik```)
|
Prefix for nomad service tags. (Default: ```traefik```)
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,7 @@
|
||||||
prefix = "foobar"
|
prefix = "foobar"
|
||||||
stale = true
|
stale = true
|
||||||
namespace = "foobar"
|
namespace = "foobar"
|
||||||
|
namespaces = ["foobar", "foobar"]
|
||||||
exposedByDefault = true
|
exposedByDefault = true
|
||||||
refreshInterval = "42s"
|
refreshInterval = "42s"
|
||||||
[providers.nomad.endpoint]
|
[providers.nomad.endpoint]
|
||||||
|
|
|
@ -195,6 +195,9 @@ providers:
|
||||||
prefix: foobar
|
prefix: foobar
|
||||||
stale: true
|
stale: true
|
||||||
namespace: foobar
|
namespace: foobar
|
||||||
|
namespaces:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
exposedByDefault: true
|
exposedByDefault: true
|
||||||
refreshInterval: 42s
|
refreshInterval: 42s
|
||||||
endpoint:
|
endpoint:
|
||||||
|
|
|
@ -295,7 +295,7 @@ Kubernetes cluster before creating `TCPRoute` objects.
|
||||||
```
|
```
|
||||||
|
|
||||||
| Ref | Attribute | Description |
|
| Ref | Attribute | Description |
|
||||||
|------|---------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|------|---------------|------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| [1] | `parentRefs` | References the resources (usually Gateways) that a Route wants to be attached to. |
|
| [1] | `parentRefs` | References the resources (usually Gateways) that a Route wants to be attached to. |
|
||||||
| [2] | `name` | Name of the referent. |
|
| [2] | `name` | Name of the referent. |
|
||||||
| [3] | `namespace` | Namespace of the referent. When unspecified (or empty string), this refers to the local namespace of the Route. |
|
| [3] | `namespace` | Namespace of the referent. When unspecified (or empty string), this refers to the local namespace of the Route. |
|
||||||
|
@ -305,7 +305,7 @@ Kubernetes cluster before creating `TCPRoute` objects.
|
||||||
| [7] | `name` | The name of the referent service. |
|
| [7] | `name` | The name of the referent service. |
|
||||||
| [8] | `weight` | The proportion of traffic forwarded to a targetRef, computed as weight/(sum of all weights in targetRefs). |
|
| [8] | `weight` | The proportion of traffic forwarded to a targetRef, computed as weight/(sum of all weights in targetRefs). |
|
||||||
| [9] | `port` | The port of the referent service. |
|
| [9] | `port` | The port of the referent service. |
|
||||||
| [10] | `group` | Group is the group of the referent. Only traefik.io`, `traefik.containo.us` and `gateway.networking.k8s.io` values are supported. |
|
| [10] | `group` | Group is the group of the referent. Only `traefik.io`, `traefik.containo.us` and `gateway.networking.k8s.io` values are supported. |
|
||||||
| [11] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. |
|
| [11] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. |
|
||||||
|
|
||||||
### Kind: `TLSRoute`
|
### Kind: `TLSRoute`
|
||||||
|
@ -341,7 +341,7 @@ Kubernetes cluster before creating `TLSRoute` objects.
|
||||||
```
|
```
|
||||||
|
|
||||||
| Ref | Attribute | Description |
|
| Ref | Attribute | Description |
|
||||||
|------|---------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|------|---------------|------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| [1] | `parentRefs` | References the resources (usually Gateways) that a Route wants to be attached to. |
|
| [1] | `parentRefs` | References the resources (usually Gateways) that a Route wants to be attached to. |
|
||||||
| [2] | `name` | Name of the referent. |
|
| [2] | `name` | Name of the referent. |
|
||||||
| [3] | `namespace` | Namespace of the referent. When unspecified (or empty string), this refers to the local namespace of the Route. |
|
| [3] | `namespace` | Namespace of the referent. When unspecified (or empty string), this refers to the local namespace of the Route. |
|
||||||
|
@ -352,5 +352,5 @@ Kubernetes cluster before creating `TLSRoute` objects.
|
||||||
| [8] | `name` | The name of the referent service. |
|
| [8] | `name` | The name of the referent service. |
|
||||||
| [9] | `weight` | The proportion of traffic forwarded to a targetRef, computed as weight/(sum of all weights in targetRefs). |
|
| [9] | `weight` | The proportion of traffic forwarded to a targetRef, computed as weight/(sum of all weights in targetRefs). |
|
||||||
| [10] | `port` | The port of the referent service. |
|
| [10] | `port` | The port of the referent service. |
|
||||||
| [11] | `group` | Group is the group of the referent. Only traefik.io`, `traefik.containo.us` and `gateway.networking.k8s.io` values are supported. |
|
| [11] | `group` | Group is the group of the referent. Only `traefik.io`, `traefik.containo.us` and `gateway.networking.k8s.io` values are supported. |
|
||||||
| [12] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. |
|
| [12] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. |
|
||||||
|
|
|
@ -171,7 +171,6 @@
|
||||||
samplingType = "foobar"
|
samplingType = "foobar"
|
||||||
samplingParam = 42.0
|
samplingParam = 42.0
|
||||||
localAgentHostPort = "foobar"
|
localAgentHostPort = "foobar"
|
||||||
localAgentSocket = "foobar"
|
|
||||||
gen128Bit = true
|
gen128Bit = true
|
||||||
propagation = "foobar"
|
propagation = "foobar"
|
||||||
traceContextHeaderName = "foobar"
|
traceContextHeaderName = "foobar"
|
||||||
|
|
|
@ -186,7 +186,7 @@ type Providers struct {
|
||||||
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.ProviderBuilder `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"`
|
||||||
Nomad *nomad.Provider `description:"Enable Nomad backend with default settings." json:"nomad,omitempty" toml:"nomad,omitempty" yaml:"nomad,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
Nomad *nomad.ProviderBuilder `description:"Enable Nomad backend with default settings." json:"nomad,omitempty" toml:"nomad,omitempty" yaml:"nomad,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.ProviderBuilder `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"`
|
||||||
|
@ -326,11 +326,15 @@ func (c *Configuration) ValidateConfiguration() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Providers.ConsulCatalog != nil && c.Providers.ConsulCatalog.Namespace != "" && len(c.Providers.ConsulCatalog.Namespaces) > 0 {
|
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")
|
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 {
|
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 fmt.Errorf("Consul provider cannot have both namespace and namespaces options configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Providers.Nomad != nil && c.Providers.Nomad.Namespace != "" && len(c.Providers.Nomad.Namespaces) > 0 {
|
||||||
|
return fmt.Errorf("Nomad provider cannot have both namespace and namespaces options configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -115,7 +115,9 @@ func NewProviderAggregator(conf static.Providers) ProviderAggregator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.Nomad != nil {
|
if conf.Nomad != nil {
|
||||||
p.quietAddProvider(conf.Nomad)
|
for _, pvd := range conf.Nomad.BuildProviders() {
|
||||||
|
p.quietAddProvider(pvd)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.Consul != nil {
|
if conf.Consul != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||||
)
|
)
|
||||||
|
@ -2509,5 +2510,57 @@ func Test_keepItem(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, extractNamespacesFromProvider(pb.BuildProviders()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractNamespacesFromProvider(providers []*Provider) []string {
|
||||||
|
res := make([]string, len(providers))
|
||||||
|
for i, p := range providers {
|
||||||
|
res[i] = p.namespace
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func Int(v int) *int { return &v }
|
func Int(v int) *int { return &v }
|
||||||
func Bool(v bool) *bool { return &v }
|
func Bool(v bool) *bool { return &v }
|
||||||
|
|
|
@ -2,6 +2,7 @@ package nomad
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
@ -46,17 +47,79 @@ type item struct {
|
||||||
ExtraConf configuration // global options
|
ExtraConf configuration // global options
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provider holds configurations of the provider.
|
// ProviderBuilder is responsible for constructing namespaced instances of the Nomad provider.
|
||||||
type Provider struct {
|
type ProviderBuilder struct {
|
||||||
|
Configuration `yaml:",inline" export:"true"`
|
||||||
|
|
||||||
|
// Deprecated: Use Namespaces option instead
|
||||||
|
Namespace string `description:"Sets the Nomad namespace used to discover services." json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
|
Namespaces []string `description:"Sets the Nomad namespaces used to discover services." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildProviders builds Nomad provider instances for the given namespaces configuration.
|
||||||
|
func (p *ProviderBuilder) BuildProviders() []*Provider {
|
||||||
|
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 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 Nomad provider configuration.
|
||||||
|
type Configuration struct {
|
||||||
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
|
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
|
||||||
Constraints string `description:"Constraints is an expression that Traefik matches against the Nomad service's tags to determine whether to create route(s) for that service." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
|
Constraints string `description:"Constraints is an expression that Traefik matches against the Nomad service's tags to determine whether to create route(s) for that service." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
|
||||||
Endpoint *EndpointConfig `description:"Nomad endpoint settings" json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"`
|
Endpoint *EndpointConfig `description:"Nomad endpoint settings" json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"`
|
||||||
Prefix string `description:"Prefix for nomad service tags." json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"`
|
Prefix string `description:"Prefix for nomad service tags." json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,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"`
|
||||||
Namespace string `description:"Sets the Nomad namespace used to discover services." json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty" export:"true"`
|
|
||||||
ExposedByDefault bool `description:"Expose Nomad services by default." json:"exposedByDefault,omitempty" toml:"exposedByDefault,omitempty" yaml:"exposedByDefault,omitempty" export:"true"`
|
ExposedByDefault bool `description:"Expose Nomad services by default." json:"exposedByDefault,omitempty" toml:"exposedByDefault,omitempty" yaml:"exposedByDefault,omitempty" export:"true"`
|
||||||
RefreshInterval ptypes.Duration `description:"Interval for polling Nomad API." json:"refreshInterval,omitempty" toml:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty" export:"true"`
|
RefreshInterval ptypes.Duration `description:"Interval for polling Nomad API." json:"refreshInterval,omitempty" toml:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty" export:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaults sets the default values for the Nomad Traefik Provider Configuration.
|
||||||
|
func (c *Configuration) SetDefaults() {
|
||||||
|
defConfig := api.DefaultConfig()
|
||||||
|
c.Endpoint = &EndpointConfig{
|
||||||
|
Address: defConfig.Address,
|
||||||
|
Region: defConfig.Region,
|
||||||
|
Token: defConfig.SecretID,
|
||||||
|
TLS: &types.ClientTLS{
|
||||||
|
CA: defConfig.TLSConfig.CACert,
|
||||||
|
Cert: defConfig.TLSConfig.ClientCert,
|
||||||
|
Key: defConfig.TLSConfig.ClientKey,
|
||||||
|
InsecureSkipVerify: defConfig.TLSConfig.Insecure,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c.Prefix = defaultPrefix
|
||||||
|
c.ExposedByDefault = true
|
||||||
|
c.RefreshInterval = ptypes.Duration(15 * time.Second)
|
||||||
|
c.DefaultRule = defaultTemplateRule
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider holds configuration along with the namespace it will discover services in.
|
||||||
|
type Provider struct {
|
||||||
|
Configuration
|
||||||
|
|
||||||
|
name string
|
||||||
|
namespace string
|
||||||
client *api.Client // client for Nomad API
|
client *api.Client // client for Nomad API
|
||||||
defaultRuleTpl *template.Template // default routing rule
|
defaultRuleTpl *template.Template // default routing rule
|
||||||
}
|
}
|
||||||
|
@ -74,31 +137,26 @@ type EndpointConfig struct {
|
||||||
|
|
||||||
// SetDefaults sets the default values for the Nomad Traefik Provider.
|
// SetDefaults sets the default values for the Nomad Traefik Provider.
|
||||||
func (p *Provider) SetDefaults() {
|
func (p *Provider) SetDefaults() {
|
||||||
defConfig := api.DefaultConfig()
|
p.Configuration.SetDefaults()
|
||||||
p.Endpoint = &EndpointConfig{
|
|
||||||
Address: defConfig.Address,
|
|
||||||
Region: defConfig.Region,
|
|
||||||
Token: defConfig.SecretID,
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: defConfig.TLSConfig.CACert,
|
|
||||||
Cert: defConfig.TLSConfig.ClientCert,
|
|
||||||
Key: defConfig.TLSConfig.ClientKey,
|
|
||||||
InsecureSkipVerify: defConfig.TLSConfig.Insecure,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
p.Prefix = defaultPrefix
|
|
||||||
p.ExposedByDefault = true
|
|
||||||
p.RefreshInterval = ptypes.Duration(15 * time.Second)
|
|
||||||
p.DefaultRule = defaultTemplateRule
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init the Nomad Traefik Provider.
|
// Init the Nomad Traefik Provider.
|
||||||
func (p *Provider) Init() error {
|
func (p *Provider) Init() error {
|
||||||
|
if p.namespace == api.AllNamespacesNamespace {
|
||||||
|
return errors.New("wildcard namespace not supported")
|
||||||
|
}
|
||||||
|
|
||||||
defaultRuleTpl, err := provider.MakeDefaultRuleTemplate(p.DefaultRule, nil)
|
defaultRuleTpl, err := provider.MakeDefaultRuleTemplate(p.DefaultRule, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while parsing default rule: %w", err)
|
return fmt.Errorf("error while parsing default rule: %w", err)
|
||||||
}
|
}
|
||||||
p.defaultRuleTpl = defaultRuleTpl
|
p.defaultRuleTpl = defaultRuleTpl
|
||||||
|
|
||||||
|
// In case they didn't initialize Provider with BuildProviders
|
||||||
|
if p.name == "" {
|
||||||
|
p.name = providerName
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,13 +164,13 @@ func (p *Provider) Init() error {
|
||||||
// using the given configuration channel.
|
// 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 nomad API client: %w", err)
|
return fmt.Errorf("failed to create nomad API client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.GoCtx(func(routineCtx context.Context) {
|
pool.GoCtx(func(routineCtx context.Context) {
|
||||||
ctxLog := log.With(routineCtx, log.Str(log.ProviderName, providerName))
|
ctxLog := log.With(routineCtx, log.Str(log.ProviderName, p.name))
|
||||||
logger := log.FromContext(ctxLog)
|
logger := log.FromContext(ctxLog)
|
||||||
|
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
|
@ -165,7 +223,7 @@ func (p *Provider) loadConfiguration(ctx context.Context, configurationC chan<-
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
configurationC <- dynamic.Message{
|
configurationC <- dynamic.Message{
|
||||||
ProviderName: providerName,
|
ProviderName: p.name,
|
||||||
Configuration: p.buildConfig(ctx, items),
|
Configuration: p.buildConfig(ctx, items),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,12 @@ func Test_globalConfig(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range cases {
|
for _, test := range cases {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
p := Provider{ExposedByDefault: test.ExposedByDefault, Prefix: test.Prefix}
|
p := Provider{
|
||||||
|
Configuration: Configuration{
|
||||||
|
ExposedByDefault: test.ExposedByDefault,
|
||||||
|
Prefix: test.Prefix,
|
||||||
|
},
|
||||||
|
}
|
||||||
result := p.getExtraConf(test.Tags)
|
result := p.getExtraConf(test.Tags)
|
||||||
require.Equal(t, test.exp, result)
|
require.Equal(t, test.exp, result)
|
||||||
})
|
})
|
||||||
|
@ -148,7 +153,7 @@ func Test_getNomadServiceData(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// fudge client, avoid starting up via Provide
|
// fudge client, avoid starting up via Provide
|
||||||
p.client, err = createClient(p.Namespace, p.Endpoint)
|
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// make the query for services
|
// make the query for services
|
||||||
|
|
|
@ -1157,6 +1157,9 @@ export default {
|
||||||
if (name.startsWith('consulcatalog-')) {
|
if (name.startsWith('consulcatalog-')) {
|
||||||
return `statics/providers/consulcatalog.svg`
|
return `statics/providers/consulcatalog.svg`
|
||||||
}
|
}
|
||||||
|
if (name.startsWith('nomad-')) {
|
||||||
|
return `statics/providers/nomad.svg`
|
||||||
|
}
|
||||||
|
|
||||||
return `statics/providers/${name}.svg`
|
return `statics/providers/${name}.svg`
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,9 @@ export default {
|
||||||
if (name.startsWith('consulcatalog-')) {
|
if (name.startsWith('consulcatalog-')) {
|
||||||
return `statics/providers/consulcatalog.svg`
|
return `statics/providers/consulcatalog.svg`
|
||||||
}
|
}
|
||||||
|
if (name.startsWith('nomad-')) {
|
||||||
|
return `statics/providers/nomad.svg`
|
||||||
|
}
|
||||||
|
|
||||||
return `statics/providers/${name}.svg`
|
return `statics/providers/${name}.svg`
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,9 @@ export default {
|
||||||
if (name.startsWith('consulcatalog-')) {
|
if (name.startsWith('consulcatalog-')) {
|
||||||
return `statics/providers/consulcatalog.svg`
|
return `statics/providers/consulcatalog.svg`
|
||||||
}
|
}
|
||||||
|
if (name.startsWith('nomad-')) {
|
||||||
|
return `statics/providers/nomad.svg`
|
||||||
|
}
|
||||||
|
|
||||||
return `statics/providers/${name}.svg`
|
return `statics/providers/${name}.svg`
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,6 +155,9 @@ export default {
|
||||||
if (name.startsWith('consulcatalog-')) {
|
if (name.startsWith('consulcatalog-')) {
|
||||||
return `statics/providers/consulcatalog.svg`
|
return `statics/providers/consulcatalog.svg`
|
||||||
}
|
}
|
||||||
|
if (name.startsWith('nomad-')) {
|
||||||
|
return `statics/providers/nomad.svg`
|
||||||
|
}
|
||||||
|
|
||||||
return `statics/providers/${name}.svg`
|
return `statics/providers/${name}.svg`
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,9 @@ export default {
|
||||||
if (name.startsWith('consulcatalog-')) {
|
if (name.startsWith('consulcatalog-')) {
|
||||||
return `statics/providers/consulcatalog.svg`
|
return `statics/providers/consulcatalog.svg`
|
||||||
}
|
}
|
||||||
|
if (name.startsWith('nomad-')) {
|
||||||
|
return `statics/providers/nomad.svg`
|
||||||
|
}
|
||||||
|
|
||||||
return `statics/providers/${name}.svg`
|
return `statics/providers/${name}.svg`
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,9 @@ export default {
|
||||||
if (name.startsWith('consulcatalog-')) {
|
if (name.startsWith('consulcatalog-')) {
|
||||||
return `statics/providers/consulcatalog.svg`
|
return `statics/providers/consulcatalog.svg`
|
||||||
}
|
}
|
||||||
|
if (name.startsWith('nomad-')) {
|
||||||
|
return `statics/providers/nomad.svg`
|
||||||
|
}
|
||||||
|
|
||||||
return `statics/providers/${name}.svg`
|
return `statics/providers/${name}.svg`
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ export default {
|
||||||
if (name.startsWith('consulcatalog-')) {
|
if (name.startsWith('consulcatalog-')) {
|
||||||
return `statics/providers/consulcatalog.svg`
|
return `statics/providers/consulcatalog.svg`
|
||||||
}
|
}
|
||||||
|
if (name.startsWith('nomad-')) {
|
||||||
|
return `statics/providers/nomad.svg`
|
||||||
|
}
|
||||||
|
|
||||||
return `statics/providers/${name}.svg`
|
return `statics/providers/${name}.svg`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue