Support YAML for the dynamic configuration.
This commit is contained in:
parent
96962dd21f
commit
e69d4cba88
36 changed files with 1529 additions and 289 deletions
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue