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 (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
fmtlog "log"
|
stdlog "log"
|
||||||
|
|
||||||
"github.com/containous/flaeg"
|
"github.com/containous/flaeg"
|
||||||
"github.com/containous/staert"
|
"github.com/containous/staert"
|
||||||
|
@ -29,15 +29,44 @@ func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfigurat
|
||||||
if kv == nil {
|
if kv == nil {
|
||||||
return fmt.Errorf("error using command storeconfig, no Key-value store defined")
|
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)
|
jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmtlog.Printf("Storing configuration: %s\n", jsonConf)
|
stdlog.Printf("Storing configuration: %s\n", jsonConf)
|
||||||
|
|
||||||
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
|
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if traefikConfiguration.GlobalConfiguration.ACME != nil && len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
|
||||||
// convert ACME json file to KV store
|
// convert ACME json file to KV store
|
||||||
localStore := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
|
localStore := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
|
||||||
|
@ -45,11 +74,13 @@ func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfigurat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
meta := cluster.NewMetadata(object)
|
meta := cluster.NewMetadata(object)
|
||||||
err = meta.Marshall()
|
err = meta.Marshall()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
source := staert.KvSource{
|
source := staert.KvSource{
|
||||||
Store: kv,
|
Store: kv,
|
||||||
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
|
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).
|
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.
|
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 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:
|
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
|
```toml
|
||||||
|
|
|
@ -332,10 +332,10 @@ func (s *ConsulSuite) TestCommandStoreConfig(c *check.C) {
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
// wait for traefik finish without error
|
// wait for traefik finish without error
|
||||||
cmd.Wait()
|
err = cmd.Wait()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
//CHECK
|
expectedData := map[string]string{
|
||||||
checkmap := map[string]string{
|
|
||||||
"/traefik/loglevel": "DEBUG",
|
"/traefik/loglevel": "DEBUG",
|
||||||
"/traefik/defaultentrypoints/0": "http",
|
"/traefik/defaultentrypoints/0": "http",
|
||||||
"/traefik/entrypoints/http/address": ":8000",
|
"/traefik/entrypoints/http/address": ":8000",
|
||||||
|
@ -343,7 +343,7 @@ func (s *ConsulSuite) TestCommandStoreConfig(c *check.C) {
|
||||||
"/traefik/consul/endpoint": consulHost + ":8500",
|
"/traefik/consul/endpoint": consulHost + ":8500",
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range checkmap {
|
for key, value := range expectedData {
|
||||||
var p *store.KVPair
|
var p *store.KVPair
|
||||||
err = try.Do(60*time.Second, func() error {
|
err = try.Do(60*time.Second, func() error {
|
||||||
p, err = s.kv.Get(key, nil)
|
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 {
|
type TestStruct struct {
|
||||||
String string
|
String string
|
||||||
Int int
|
Int int
|
||||||
|
|
|
@ -28,7 +28,7 @@ type Provider struct {
|
||||||
// Provide allows the file provider to provide configurations to traefik
|
// Provide allows the file provider to provide configurations to traefik
|
||||||
// using the given configuration channel.
|
// using the given configuration channel.
|
||||||
func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -52,6 +52,15 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
return nil
|
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 {
|
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()
|
watcher, err := fsnotify.NewWatcher()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -88,6 +97,27 @@ func (p *Provider) addWatcher(pool *safe.Pool, directory string, configurationCh
|
||||||
return nil
|
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) {
|
func sendConfigToChannel(configurationChan chan<- types.ConfigMessage, configuration *types.Configuration) {
|
||||||
configurationChan <- types.ConfigMessage{
|
configurationChan <- types.ConfigMessage{
|
||||||
ProviderName: "file",
|
ProviderName: "file",
|
||||||
|
@ -168,32 +198,3 @@ func loadFileConfigFromDirectory(directory string, configuration *types.Configur
|
||||||
}
|
}
|
||||||
return configuration, nil
|
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