Add file to storeconfig
This commit is contained in:
parent
0f3e42d463
commit
7ddefcef72
4 changed files with 119 additions and 36 deletions
|
@ -3,7 +3,7 @@ package main
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
fmtlog "log"
|
||||
stdlog "log"
|
||||
|
||||
"github.com/containous/flaeg"
|
||||
"github.com/containous/staert"
|
||||
|
@ -29,15 +29,44 @@ func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfigurat
|
|||
if kv == nil {
|
||||
return fmt.Errorf("error using command storeconfig, no Key-value store defined")
|
||||
}
|
||||
|
||||
fileConfig := traefikConfiguration.GlobalConfiguration.File
|
||||
if fileConfig != nil {
|
||||
traefikConfiguration.GlobalConfiguration.File = nil
|
||||
if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 {
|
||||
fileConfig.Filename = traefikConfiguration.ConfigFile
|
||||
}
|
||||
}
|
||||
|
||||
jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmtlog.Printf("Storing configuration: %s\n", jsonConf)
|
||||
stdlog.Printf("Storing configuration: %s\n", jsonConf)
|
||||
|
||||
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fileConfig != nil {
|
||||
jsonConf, err = json.Marshal(fileConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stdlog.Printf("Storing file configuration: %s\n", jsonConf)
|
||||
config, err := fileConfig.LoadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stdlog.Print("Writing config to KV")
|
||||
err = kv.StoreConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if traefikConfiguration.GlobalConfiguration.ACME != nil && len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
|
||||
// convert ACME json file to KV store
|
||||
localStore := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
|
||||
|
@ -45,11 +74,13 @@ func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfigurat
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
meta := cluster.NewMetadata(object)
|
||||
err = meta.Marshall()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source := staert.KvSource{
|
||||
Store: kv,
|
||||
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
|
||||
|
|
|
@ -378,8 +378,11 @@ traefik storeconfig [flags] ...
|
|||
```
|
||||
This command is here only to automate the [process which upload the configuration into the Key-value store](/user-guide/kv-config/#upload-the-configuration-in-the-key-value-store).
|
||||
Træfik will not start but the [static configuration](/basics/#static-trfk-configuration) will be uploaded into the Key-value store.
|
||||
|
||||
If you configured ACME (Let's Encrypt), your registration account and your certificates will also be uploaded.
|
||||
|
||||
If you configured a file backend `[file]`, all your dynamic configuration (backends, frontends...) will be uploaded to the Key-value store.
|
||||
|
||||
To upload your ACME certificates to the KV store, get your Traefik TOML file and add the new `storage` option in the `acme` section:
|
||||
|
||||
```toml
|
||||
|
|
|
@ -332,10 +332,10 @@ func (s *ConsulSuite) TestCommandStoreConfig(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// wait for traefik finish without error
|
||||
cmd.Wait()
|
||||
err = cmd.Wait()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
//CHECK
|
||||
checkmap := map[string]string{
|
||||
expectedData := map[string]string{
|
||||
"/traefik/loglevel": "DEBUG",
|
||||
"/traefik/defaultentrypoints/0": "http",
|
||||
"/traefik/entrypoints/http/address": ":8000",
|
||||
|
@ -343,7 +343,7 @@ func (s *ConsulSuite) TestCommandStoreConfig(c *check.C) {
|
|||
"/traefik/consul/endpoint": consulHost + ":8500",
|
||||
}
|
||||
|
||||
for key, value := range checkmap {
|
||||
for key, value := range expectedData {
|
||||
var p *store.KVPair
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
p, err = s.kv.Get(key, nil)
|
||||
|
@ -355,6 +355,54 @@ func (s *ConsulSuite) TestCommandStoreConfig(c *check.C) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *ConsulSuite) TestCommandStoreConfigWithFile(c *check.C) {
|
||||
s.setupConsul(c)
|
||||
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
|
||||
|
||||
cmd, display := s.traefikCmd(
|
||||
"storeconfig",
|
||||
withConfigFile("fixtures/simple_default.toml"),
|
||||
"--consul.endpoint="+consulHost+":8500",
|
||||
"--file.filename=fixtures/file/dir/simple1.toml")
|
||||
defer display(c)
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// wait for traefik finish without error
|
||||
err = cmd.Wait()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
expectedData := map[string]string{
|
||||
"/traefik/backends/backend1/servers/server1/url": "http://172.17.0.2:80",
|
||||
"/traefik/frontends/frontend1/backend": "backend1",
|
||||
"/traefik/frontends/frontend1/routes/test_1/rule": "Path:/test1",
|
||||
}
|
||||
|
||||
for key, value := range expectedData {
|
||||
var p *store.KVPair
|
||||
err = try.Do(10*time.Second, func() error {
|
||||
p, err = s.kv.Get(key, nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(p.Value), checker.Equals, value)
|
||||
}
|
||||
|
||||
checkNotExistsMap := []string{
|
||||
"/traefik/file",
|
||||
}
|
||||
|
||||
for _, value := range checkNotExistsMap {
|
||||
err = try.Do(10*time.Second, func() error {
|
||||
if exists, err := s.kv.Exists(value, nil); err == nil && exists {
|
||||
return fmt.Errorf("%s key is not suppose to exist in KV", value)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
||||
|
||||
type TestStruct struct {
|
||||
String string
|
||||
Int int
|
||||
|
|
|
@ -28,7 +28,7 @@ type Provider struct {
|
|||
// Provide allows the file provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
configuration, err := p.loadConfig()
|
||||
configuration, err := p.LoadConfig()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -52,6 +52,15 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
|||
return nil
|
||||
}
|
||||
|
||||
// LoadConfig loads configuration either from file or a directory specified by 'Filename'/'Directory'
|
||||
// and returns a 'Configuration' object
|
||||
func (p *Provider) LoadConfig() (*types.Configuration, error) {
|
||||
if p.Directory != "" {
|
||||
return loadFileConfigFromDirectory(p.Directory, nil)
|
||||
}
|
||||
return loadFileConfig(p.Filename)
|
||||
}
|
||||
|
||||
func (p *Provider) addWatcher(pool *safe.Pool, directory string, configurationChan chan<- types.ConfigMessage, callback func(chan<- types.ConfigMessage, fsnotify.Event)) error {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
|
@ -88,6 +97,27 @@ func (p *Provider) addWatcher(pool *safe.Pool, directory string, configurationCh
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *Provider) watcherCallback(configurationChan chan<- types.ConfigMessage, event fsnotify.Event) {
|
||||
watchItem := p.Filename
|
||||
if p.Directory != "" {
|
||||
watchItem = p.Directory
|
||||
}
|
||||
|
||||
if _, err := os.Stat(watchItem); err != nil {
|
||||
log.Debugf("Unable to watch %s : %v", watchItem, err)
|
||||
return
|
||||
}
|
||||
|
||||
configuration, err := p.LoadConfig()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred during watcher callback: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
sendConfigToChannel(configurationChan, configuration)
|
||||
}
|
||||
|
||||
func sendConfigToChannel(configurationChan chan<- types.ConfigMessage, configuration *types.Configuration) {
|
||||
configurationChan <- types.ConfigMessage{
|
||||
ProviderName: "file",
|
||||
|
@ -168,32 +198,3 @@ func loadFileConfigFromDirectory(directory string, configuration *types.Configur
|
|||
}
|
||||
return configuration, nil
|
||||
}
|
||||
|
||||
func (p *Provider) watcherCallback(configurationChan chan<- types.ConfigMessage, event fsnotify.Event) {
|
||||
watchItem := p.Filename
|
||||
if p.Directory != "" {
|
||||
watchItem = p.Directory
|
||||
}
|
||||
|
||||
if _, err := os.Stat(watchItem); err != nil {
|
||||
log.Debugf("Unable to watch %s : %v", watchItem, err)
|
||||
return
|
||||
}
|
||||
|
||||
configuration, err := p.loadConfig()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred during watcher callback: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
sendConfigToChannel(configurationChan, configuration)
|
||||
}
|
||||
|
||||
func (p *Provider) loadConfig() (*types.Configuration, error) {
|
||||
if p.Directory != "" {
|
||||
return loadFileConfigFromDirectory(p.Directory, nil)
|
||||
}
|
||||
|
||||
return loadFileConfig(p.Filename)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue