diff --git a/cmd/configuration.go b/cmd/configuration.go index e268e94a5..c5f128109 100644 --- a/cmd/configuration.go +++ b/cmd/configuration.go @@ -171,7 +171,6 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration { // default Kubernetes var defaultKubernetes ingress.Provider - defaultKubernetes.Watch = true defaultProviders := static.Providers{ File: &defaultFile, diff --git a/pkg/anonymize/anonymize_config_test.go b/pkg/anonymize/anonymize_config_test.go index 27d11e9b0..1d0f132aa 100644 --- a/pkg/anonymize/anonymize_config_test.go +++ b/pkg/anonymize/anonymize_config_test.go @@ -25,7 +25,6 @@ import ( ) func TestDo_globalConfiguration(t *testing.T) { - config := &static.Configuration{} sendAnonymousUsage := true @@ -148,9 +147,15 @@ func TestDo_globalConfiguration(t *testing.T) { } config.Providers.File = &file.Provider{ - BaseProvider: provider.BaseProvider{ - Watch: true, - Filename: "file Filename", + Directory: "file Directory", + Watch: true, + Filename: "file Filename", + DebugLogGeneratedTemplate: true, + TraefikFile: "", + } + + config.Providers.Docker = &docker.Provider{ + Constrainer: provider.Constrainer{ Constraints: types.Constraints{ { Key: "file Constraints Key 1", @@ -163,20 +168,8 @@ func TestDo_globalConfiguration(t *testing.T) { MustMatch: true, }, }, - Trace: true, - DebugLogGeneratedTemplate: true, - }, - Directory: "file Directory", - } - - config.Providers.Docker = &docker.Provider{ - BaseProvider: provider.BaseProvider{ - Watch: true, - Filename: "myfilename", - Constraints: nil, - Trace: true, - DebugLogGeneratedTemplate: true, }, + Watch: true, Endpoint: "MyEndPoint", DefaultRule: "PathPrefix(`/`)", TLS: &types.ClientTLS{ @@ -194,24 +187,6 @@ func TestDo_globalConfiguration(t *testing.T) { } config.Providers.Kubernetes = &ingress.Provider{ - BaseProvider: provider.BaseProvider{ - Watch: true, - Filename: "myFileName", - Constraints: types.Constraints{ - { - Key: "k8s Constraints Key 1", - Regex: "k8s Constraints Regex 2", - MustMatch: true, - }, - { - Key: "k8s Constraints Key 1", - Regex: "k8s Constraints Regex 2", - MustMatch: true, - }, - }, - Trace: true, - DebugLogGeneratedTemplate: true, - }, Endpoint: "MyEndpoint", Token: "MyToken", CertAuthFilePath: "MyCertAuthPath", @@ -222,24 +197,6 @@ func TestDo_globalConfiguration(t *testing.T) { } config.Providers.KubernetesCRD = &crd.Provider{ - BaseProvider: provider.BaseProvider{ - Watch: true, - Filename: "myFileName", - Constraints: types.Constraints{ - { - Key: "k8s Constraints Key 1", - Regex: "k8s Constraints Regex 2", - MustMatch: true, - }, - { - Key: "k8s Constraints Key 1", - Regex: "k8s Constraints Regex 2", - MustMatch: true, - }, - }, - Trace: true, - DebugLogGeneratedTemplate: true, - }, Endpoint: "MyEndpoint", Token: "MyToken", CertAuthFilePath: "MyCertAuthPath", diff --git a/pkg/provider/base_provider.go b/pkg/provider/base_provider.go deleted file mode 100644 index 5192a9e75..000000000 --- a/pkg/provider/base_provider.go +++ /dev/null @@ -1,105 +0,0 @@ -package provider - -import ( - "bytes" - "strings" - "text/template" - - "github.com/BurntSushi/toml" - "github.com/Masterminds/sprig" - "github.com/containous/traefik/pkg/config" - "github.com/containous/traefik/pkg/log" - "github.com/containous/traefik/pkg/tls" - "github.com/containous/traefik/pkg/types" -) - -// BaseProvider should be inherited by providers. -type BaseProvider struct { - Watch bool `description:"Watch provider" export:"true"` - Filename string `description:"Override default configuration template. For advanced users :)" export:"true"` - Constraints types.Constraints `description:"Filter services by constraint, matching with Traefik tags." export:"true"` - Trace bool `description:"Display additional provider logs (if available)." export:"true"` - DebugLogGeneratedTemplate bool `description:"Enable debug logging of generated configuration template." export:"true"` -} - -// Init for compatibility reason the BaseProvider implements an empty Init. -func (p *BaseProvider) Init() error { - return nil -} - -// MatchConstraints must match with EVERY single constraint -// returns first constraint that do not match or nil. -func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint) { - // if there is no tags and no constraints, filtering is disabled - if len(tags) == 0 && len(p.Constraints) == 0 { - return true, nil - } - - for _, constraint := range p.Constraints { - // xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint - if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch { - return false, constraint - } - } - - // If no constraint or every constraints matching - return true, nil -} - -// CreateConfiguration creates a provider configuration from content using templating. -func (p *BaseProvider) CreateConfiguration(tmplContent string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) { - var defaultFuncMap = sprig.TxtFuncMap() - // tolower is deprecated in favor of sprig's lower function - defaultFuncMap["tolower"] = strings.ToLower - defaultFuncMap["normalize"] = Normalize - defaultFuncMap["split"] = split - for funcID, funcElement := range funcMap { - defaultFuncMap[funcID] = funcElement - } - - tmpl := template.New(p.Filename).Funcs(defaultFuncMap) - - _, err := tmpl.Parse(tmplContent) - if err != nil { - return nil, err - } - - var buffer bytes.Buffer - err = tmpl.Execute(&buffer, templateObjects) - if err != nil { - return nil, err - } - - var renderedTemplate = buffer.String() - if p.DebugLogGeneratedTemplate { - log.Debugf("Template content: %s", tmplContent) - log.Debugf("Rendering results: %s", renderedTemplate) - } - return p.DecodeConfiguration(renderedTemplate) -} - -// DecodeConfiguration Decodes a *types.Configuration from a content. -func (p *BaseProvider) DecodeConfiguration(content string) (*config.Configuration, error) { - configuration := &config.Configuration{ - HTTP: &config.HTTPConfiguration{ - Routers: make(map[string]*config.Router), - Middlewares: make(map[string]*config.Middleware), - Services: make(map[string]*config.Service), - }, - TCP: &config.TCPConfiguration{ - Routers: make(map[string]*config.TCPRouter), - Services: make(map[string]*config.TCPService), - }, - TLS: make([]*tls.Configuration, 0), - TLSStores: make(map[string]tls.Store), - TLSOptions: make(map[string]tls.TLS), - } - if _, err := toml.Decode(content, configuration); err != nil { - return nil, err - } - return configuration, nil -} - -func split(sep, s string) []string { - return strings.Split(s, sep) -} diff --git a/pkg/provider/constrainer.go b/pkg/provider/constrainer.go new file mode 100644 index 000000000..44a276c51 --- /dev/null +++ b/pkg/provider/constrainer.go @@ -0,0 +1,27 @@ +package provider + +import "github.com/containous/traefik/pkg/types" + +// Constrainer Filter services by constraint, matching with Traefik tags. +type Constrainer struct { + Constraints types.Constraints `description:"Filter services by constraint, matching with Traefik tags." export:"true"` +} + +// MatchConstraints must match with EVERY single constraint +// returns first constraint that do not match or nil. +func (c *Constrainer) MatchConstraints(tags []string) (bool, *types.Constraint) { + // if there is no tags and no constraints, filtering is disabled + if len(tags) == 0 && len(c.Constraints) == 0 { + return true, nil + } + + for _, constraint := range c.Constraints { + // xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint + if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch { + return false, constraint + } + } + + // If no constraint or every constraints matching + return true, nil +} diff --git a/pkg/provider/docker/docker.go b/pkg/provider/docker/docker.go index 81aca428f..f700f5aba 100644 --- a/pkg/provider/docker/docker.go +++ b/pkg/provider/docker/docker.go @@ -41,7 +41,8 @@ var _ provider.Provider = (*Provider)(nil) // Provider holds configurations of the provider. type Provider struct { - provider.BaseProvider `mapstructure:",squash" export:"true"` + provider.Constrainer `mapstructure:",squash" export:"true"` + Watch bool `description:"Watch provider" export:"true"` Endpoint string `description:"Docker server endpoint. Can be a tcp or a unix socket endpoint"` DefaultRule string `description:"Default rule"` TLS *types.ClientTLS `description:"Enable Docker TLS support" export:"true"` @@ -61,7 +62,7 @@ func (p *Provider) Init() error { } p.defaultRuleTpl = defaultRuleTpl - return p.BaseProvider.Init() + return nil } // dockerData holds the need data to the provider. diff --git a/pkg/provider/file/file.go b/pkg/provider/file/file.go index 95f5bc6ce..805b672cd 100644 --- a/pkg/provider/file/file.go +++ b/pkg/provider/file/file.go @@ -1,6 +1,7 @@ package file import ( + "bytes" "context" "fmt" "io/ioutil" @@ -10,6 +11,8 @@ import ( "strings" "text/template" + "github.com/BurntSushi/toml" + "github.com/Masterminds/sprig" "github.com/containous/traefik/pkg/config" "github.com/containous/traefik/pkg/log" "github.com/containous/traefik/pkg/provider" @@ -25,14 +28,16 @@ var _ provider.Provider = (*Provider)(nil) // Provider holds configurations of the provider. type Provider struct { - provider.BaseProvider `mapstructure:",squash" export:"true"` - Directory string `description:"Load configuration from one or more .toml files in a directory" export:"true"` - TraefikFile string + Directory string `description:"Load configuration from one or more .toml files in a directory" export:"true"` + Watch bool `description:"Watch provider" export:"true"` + Filename string `description:"Override default configuration template. For advanced users :)" export:"true"` + DebugLogGeneratedTemplate bool `description:"Enable debug logging of generated configuration template." export:"true"` + TraefikFile string } // Init the provider func (p *Provider) Init() error { - return p.BaseProvider.Init() + return nil } // Provide allows the file provider to provide configurations to traefik @@ -305,3 +310,55 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st } return configuration, nil } + +// CreateConfiguration creates a provider configuration from content using templating. +func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) { + var defaultFuncMap = sprig.TxtFuncMap() + defaultFuncMap["normalize"] = provider.Normalize + defaultFuncMap["split"] = strings.Split + for funcID, funcElement := range funcMap { + defaultFuncMap[funcID] = funcElement + } + + tmpl := template.New(p.Filename).Funcs(defaultFuncMap) + + _, err := tmpl.Parse(tmplContent) + if err != nil { + return nil, err + } + + var buffer bytes.Buffer + err = tmpl.Execute(&buffer, templateObjects) + if err != nil { + return nil, err + } + + var renderedTemplate = buffer.String() + if p.DebugLogGeneratedTemplate { + log.Debugf("Template content: %s", tmplContent) + log.Debugf("Rendering results: %s", renderedTemplate) + } + return p.DecodeConfiguration(renderedTemplate) +} + +// DecodeConfiguration Decodes a *types.Configuration from a content. +func (p *Provider) DecodeConfiguration(content string) (*config.Configuration, error) { + configuration := &config.Configuration{ + HTTP: &config.HTTPConfiguration{ + Routers: make(map[string]*config.Router), + Middlewares: make(map[string]*config.Middleware), + Services: make(map[string]*config.Service), + }, + TCP: &config.TCPConfiguration{ + Routers: make(map[string]*config.TCPRouter), + Services: make(map[string]*config.TCPService), + }, + TLS: make([]*tls.Configuration, 0), + TLSStores: make(map[string]tls.Store), + TLSOptions: make(map[string]tls.TLS), + } + if _, err := toml.Decode(content, configuration); err != nil { + return nil, err + } + return configuration, nil +} diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index d46861a50..95e0df3d4 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -16,7 +16,6 @@ import ( "github.com/containous/traefik/pkg/config" "github.com/containous/traefik/pkg/job" "github.com/containous/traefik/pkg/log" - "github.com/containous/traefik/pkg/provider" "github.com/containous/traefik/pkg/provider/kubernetes/crd/traefik/v1alpha1" "github.com/containous/traefik/pkg/provider/kubernetes/k8s" "github.com/containous/traefik/pkg/safe" @@ -33,7 +32,6 @@ const ( // Provider holds configurations of the provider. type Provider struct { - provider.BaseProvider `mapstructure:",squash" export:"true"` Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"` Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"` CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"` @@ -78,7 +76,7 @@ func (p *Provider) newK8sClient(ctx context.Context, labelSelector string) (*cli // Init the provider. func (p *Provider) Init() error { - return p.BaseProvider.Init() + return nil } // Provide allows the k8s provider to provide configurations to traefik diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go index d60daacaa..bc567f599 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes.go +++ b/pkg/provider/kubernetes/ingress/kubernetes.go @@ -16,7 +16,6 @@ import ( "github.com/containous/traefik/pkg/config" "github.com/containous/traefik/pkg/job" "github.com/containous/traefik/pkg/log" - "github.com/containous/traefik/pkg/provider" "github.com/containous/traefik/pkg/provider/kubernetes/k8s" "github.com/containous/traefik/pkg/safe" "github.com/containous/traefik/pkg/tls" @@ -34,7 +33,6 @@ const ( // Provider holds configurations of the provider. type Provider struct { - provider.BaseProvider `mapstructure:",squash" export:"true"` Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"` Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"` CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"` @@ -90,7 +88,7 @@ func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string // Init the provider. func (p *Provider) Init() error { - return p.BaseProvider.Init() + return nil } // Provide allows the k8s provider to provide configurations to traefik diff --git a/pkg/provider/marathon/label_test.go b/pkg/provider/marathon/label_test.go index 8eee255e5..7cb011939 100644 --- a/pkg/provider/marathon/label_test.go +++ b/pkg/provider/marathon/label_test.go @@ -4,7 +4,6 @@ import ( "math" "testing" - "github.com/containous/traefik/pkg/provider" "github.com/gambol99/go-marathon" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -24,7 +23,6 @@ func TestGetConfiguration(t *testing.T) { Labels: &map[string]string{}, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: false, FilterMarathonConstraints: false, }, @@ -45,7 +43,6 @@ func TestGetConfiguration(t *testing.T) { }, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: false, FilterMarathonConstraints: false, }, @@ -66,7 +63,6 @@ func TestGetConfiguration(t *testing.T) { }, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: false, FilterMarathonConstraints: false, }, @@ -87,7 +83,6 @@ func TestGetConfiguration(t *testing.T) { Labels: &map[string]string{}, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: false, FilterMarathonConstraints: true, }, @@ -108,7 +103,6 @@ func TestGetConfiguration(t *testing.T) { Labels: &map[string]string{}, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: true, FilterMarathonConstraints: false, }, @@ -129,7 +123,6 @@ func TestGetConfiguration(t *testing.T) { }, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: true, FilterMarathonConstraints: false, }, @@ -150,7 +143,6 @@ func TestGetConfiguration(t *testing.T) { }, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: true, FilterMarathonConstraints: false, }, diff --git a/pkg/provider/marathon/marathon.go b/pkg/provider/marathon/marathon.go index 5e6268d1a..2a4ad9c73 100644 --- a/pkg/provider/marathon/marathon.go +++ b/pkg/provider/marathon/marathon.go @@ -46,7 +46,9 @@ var _ provider.Provider = (*Provider)(nil) // Provider holds configuration of the provider. type Provider struct { - provider.BaseProvider + provider.Constrainer `mapstructure:",squash" export:"true"` + Trace bool `description:"Display additional provider logs." export:"true"` + Watch bool `description:"Watch provider" export:"true"` Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon" export:"true"` DefaultRule string `description:"Default rule"` ExposedByDefault bool `description:"Expose Marathon apps by default" export:"true"` @@ -89,7 +91,7 @@ func (p *Provider) Init() error { } p.defaultRuleTpl = defaultRuleTpl - return p.BaseProvider.Init() + return nil } // Provide allows the marathon provider to provide configurations to traefik