1
0
Fork 0

Support YAML for the dynamic configuration.

This commit is contained in:
Ludovic Fernandez 2019-06-26 18:18:04 +02:00 committed by Traefiker Bot
parent 96962dd21f
commit e69d4cba88
36 changed files with 1529 additions and 289 deletions

View file

@ -7,7 +7,6 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"text/template"
@ -20,6 +19,7 @@ import (
"github.com/containous/traefik/pkg/safe"
"github.com/containous/traefik/pkg/tls"
"gopkg.in/fsnotify.v1"
"gopkg.in/yaml.v2"
)
const providerName = "file"
@ -170,28 +170,13 @@ func sendConfigToChannel(configurationChan chan<- config.Message, configuration
}
}
func readFile(filename string) (string, error) {
if len(filename) > 0 {
buf, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return string(buf), nil
}
return "", fmt.Errorf("invalid filename: %s", filename)
}
func (p *Provider) loadFileConfig(filename string, parseTemplate bool) (*config.Configuration, error) {
fileContent, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %s", filename, err)
}
var err error
var configuration *config.Configuration
if parseTemplate {
configuration, err = p.CreateConfiguration(fileContent, template.FuncMap{}, false)
configuration, err = p.CreateConfiguration(filename, template.FuncMap{}, false)
} else {
configuration, err = p.DecodeConfiguration(fileContent)
configuration, err = p.DecodeConfiguration(filename)
}
if err != nil {
return nil, err
@ -223,7 +208,6 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
logger := log.FromContext(ctx)
fileList, err := ioutil.ReadDir(directory)
if err != nil {
return configuration, fmt.Errorf("unable to read directory %s: %v", directory, err)
}
@ -243,6 +227,7 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
}
configTLSMaps := make(map[*tls.Configuration]struct{})
for _, item := range fileList {
if item.IsDir() {
@ -251,13 +236,17 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
return configuration, fmt.Errorf("unable to load content configuration from subdirectory %s: %v", item, err)
}
continue
} else if !strings.HasSuffix(item.Name(), ".toml") && !strings.HasSuffix(item.Name(), ".tmpl") {
}
switch strings.ToLower(filepath.Ext(item.Name())) {
case ".toml", ".yaml", ".yml":
// noop
default:
continue
}
var c *config.Configuration
c, err = p.loadFileConfig(path.Join(directory, item.Name()), true)
c, err = p.loadFileConfig(filepath.Join(directory, item.Name()), true)
if err != nil {
return configuration, err
}
@ -318,7 +307,12 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
}
// CreateConfiguration creates a provider configuration from content using templating.
func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) {
func (p *Provider) CreateConfiguration(filename string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) {
tmplContent, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %s", filename, err)
}
var defaultFuncMap = sprig.TxtFuncMap()
defaultFuncMap["normalize"] = provider.Normalize
defaultFuncMap["split"] = strings.Split
@ -328,7 +322,7 @@ func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.Func
tmpl := template.New(p.Filename).Funcs(defaultFuncMap)
_, err := tmpl.Parse(tmplContent)
_, err = tmpl.Parse(tmplContent)
if err != nil {
return nil, err
}
@ -341,14 +335,25 @@ func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.Func
var renderedTemplate = buffer.String()
if p.DebugLogGeneratedTemplate {
log.Debugf("Template content: %s", tmplContent)
log.Debugf("Rendering results: %s", renderedTemplate)
logger := log.WithoutContext().WithField(log.ProviderName, providerName)
logger.Debugf("Template content: %s", tmplContent)
logger.Debugf("Rendering results: %s", renderedTemplate)
}
return p.DecodeConfiguration(renderedTemplate)
return p.decodeConfiguration(filename, renderedTemplate)
}
// DecodeConfiguration Decodes a *types.Configuration from a content.
func (p *Provider) DecodeConfiguration(content string) (*config.Configuration, error) {
func (p *Provider) DecodeConfiguration(filename string) (*config.Configuration, error) {
content, err := readFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading configuration file: %s - %s", filename, err)
}
return p.decodeConfiguration(filename, content)
}
func (p *Provider) decodeConfiguration(filePath string, content string) (*config.Configuration, error) {
configuration := &config.Configuration{
HTTP: &config.HTTPConfiguration{
Routers: make(map[string]*config.Router),
@ -363,8 +368,35 @@ func (p *Provider) DecodeConfiguration(content string) (*config.Configuration, e
TLSStores: make(map[string]tls.Store),
TLSOptions: make(map[string]tls.TLS),
}
if _, err := toml.Decode(content, configuration); err != nil {
return nil, err
switch strings.ToLower(filepath.Ext(filePath)) {
case ".toml":
_, err := toml.Decode(content, configuration)
if err != nil {
return nil, err
}
case ".yml", ".yaml":
var err error
err = yaml.Unmarshal([]byte(content), configuration)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported file extension: %s", filePath)
}
return configuration, nil
}
func readFile(filename string) (string, error) {
if len(filename) > 0 {
buf, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return string(buf), nil
}
return "", fmt.Errorf("invalid filename: %s", filename)
}