2015-11-01 16:35:01 +01:00
|
|
|
package provider
|
|
|
|
|
2015-11-13 11:50:32 +01:00
|
|
|
import (
|
|
|
|
"bytes"
|
2016-12-30 09:21:13 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"strings"
|
|
|
|
"text/template"
|
|
|
|
"unicode"
|
2016-08-13 12:55:15 -04:00
|
|
|
|
2015-11-13 11:50:32 +01:00
|
|
|
"github.com/BurntSushi/toml"
|
2017-08-10 20:42:39 +02:00
|
|
|
"github.com/Masterminds/sprig"
|
2017-11-20 15:26:03 +01:00
|
|
|
"github.com/containous/traefik/autogen/gentemplates"
|
2016-09-23 18:27:01 +02:00
|
|
|
"github.com/containous/traefik/log"
|
2016-04-13 20:36:23 +02:00
|
|
|
"github.com/containous/traefik/safe"
|
2016-02-24 16:43:39 +01:00
|
|
|
"github.com/containous/traefik/types"
|
2015-11-13 11:50:32 +01:00
|
|
|
)
|
2015-11-01 16:35:01 +01:00
|
|
|
|
2015-11-01 19:29:47 +01:00
|
|
|
// Provider defines methods of a provider.
|
2015-11-01 16:35:01 +01:00
|
|
|
type Provider interface {
|
2015-11-01 19:29:47 +01:00
|
|
|
// Provide allows the provider to provide configurations to traefik
|
|
|
|
// using the given configuration channel.
|
2016-11-09 19:27:04 +01:00
|
|
|
Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error
|
2015-11-01 16:35:01 +01:00
|
|
|
}
|
2015-11-13 11:50:32 +01:00
|
|
|
|
2016-01-13 22:46:44 +01:00
|
|
|
// BaseProvider should be inherited by providers
|
|
|
|
type BaseProvider struct {
|
2017-10-02 10:32:02 +02:00
|
|
|
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"`
|
2016-05-30 15:05:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// MatchConstraints must match with EVERY single contraint
|
|
|
|
// returns first constraint that do not match or nil
|
2016-05-20 17:17:38 +02:00
|
|
|
func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint) {
|
2017-10-10 11:10:02 +02:00
|
|
|
// if there is no tags and no constraints, filtering is disabled
|
2016-05-30 15:05:58 +02:00
|
|
|
if len(tags) == 0 && len(p.Constraints) == 0 {
|
2016-05-20 17:17:38 +02:00
|
|
|
return true, nil
|
2016-05-30 15:05:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, constraint := range p.Constraints {
|
2016-05-20 17:17:38 +02:00
|
|
|
// 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 {
|
2016-11-09 19:27:04 +01:00
|
|
|
return false, constraint
|
2016-05-30 15:05:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no constraint or every constraints matching
|
2016-05-20 17:17:38 +02:00
|
|
|
return true, nil
|
2015-11-13 11:50:32 +01:00
|
|
|
}
|
|
|
|
|
2017-04-15 16:46:44 +02:00
|
|
|
// GetConfiguration return the provider configuration using templating
|
2017-04-15 15:49:53 +02:00
|
|
|
func (p *BaseProvider) GetConfiguration(defaultTemplateFile string, funcMap template.FuncMap, templateObjects interface{}) (*types.Configuration, error) {
|
2015-11-13 11:50:32 +01:00
|
|
|
configuration := new(types.Configuration)
|
2016-12-03 10:12:22 +01:00
|
|
|
|
2017-08-10 20:42:39 +02:00
|
|
|
var defaultFuncMap = sprig.TxtFuncMap()
|
|
|
|
// tolower is deprecated in favor of sprig's lower function
|
|
|
|
defaultFuncMap["tolower"] = strings.ToLower
|
|
|
|
defaultFuncMap["normalize"] = Normalize
|
|
|
|
defaultFuncMap["split"] = split
|
2016-12-03 10:12:22 +01:00
|
|
|
for funcID, funcElement := range funcMap {
|
|
|
|
defaultFuncMap[funcID] = funcElement
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpl := template.New(p.Filename).Funcs(defaultFuncMap)
|
2017-11-17 10:12:03 +01:00
|
|
|
|
|
|
|
tmplContent, err := p.getTemplateContent(defaultTemplateFile)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2015-11-13 11:50:32 +01:00
|
|
|
}
|
2017-11-17 10:12:03 +01:00
|
|
|
|
|
|
|
_, err = tmpl.Parse(tmplContent)
|
2015-11-13 11:50:32 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
err = tmpl.Execute(&buffer, templateObjects)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-08-13 12:55:15 -04:00
|
|
|
var renderedTemplate = buffer.String()
|
2017-08-21 10:46:03 +02:00
|
|
|
if p.DebugLogGeneratedTemplate {
|
|
|
|
log.Debugf("Rendering results of %s:\n%s", defaultTemplateFile, renderedTemplate)
|
|
|
|
}
|
2016-08-13 12:55:15 -04:00
|
|
|
if _, err := toml.Decode(renderedTemplate, configuration); err != nil {
|
2015-11-13 11:50:32 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return configuration, nil
|
|
|
|
}
|
|
|
|
|
2017-11-17 10:12:03 +01:00
|
|
|
func (p *BaseProvider) getTemplateContent(defaultTemplateFile string) (string, error) {
|
|
|
|
if len(p.Filename) > 0 {
|
|
|
|
buf, err := ioutil.ReadFile(p.Filename)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return string(buf), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasSuffix(defaultTemplateFile, ".tmpl") {
|
2017-11-20 15:26:03 +01:00
|
|
|
buf, err := gentemplates.Asset(defaultTemplateFile)
|
2017-11-17 10:12:03 +01:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return string(buf), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return defaultTemplateFile, nil
|
|
|
|
}
|
|
|
|
|
2016-12-03 10:12:22 +01:00
|
|
|
func split(sep, s string) []string {
|
|
|
|
return strings.Split(s, sep)
|
|
|
|
}
|
|
|
|
|
2017-04-15 16:46:44 +02:00
|
|
|
// Normalize transform a string that work with the rest of traefik
|
2017-04-15 15:49:53 +02:00
|
|
|
func Normalize(name string) string {
|
2016-03-27 01:05:17 +01:00
|
|
|
fargs := func(c rune) bool {
|
|
|
|
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
|
|
|
|
}
|
|
|
|
// get function
|
|
|
|
return strings.Join(strings.FieldsFunc(name, fargs), "-")
|
|
|
|
}
|
2016-06-27 16:14:56 +02:00
|
|
|
|
2017-04-17 12:50:02 +02:00
|
|
|
// ReverseStringSlice invert the order of the given slice of string
|
|
|
|
func ReverseStringSlice(slice *[]string) {
|
2016-11-28 08:59:08 -05:00
|
|
|
for i, j := 0, len(*slice)-1; i < j; i, j = i+1, j-1 {
|
|
|
|
(*slice)[i], (*slice)[j] = (*slice)[j], (*slice)[i]
|
|
|
|
}
|
|
|
|
}
|