traefik/cmd/storeconfig/storeconfig.go

212 lines
5.5 KiB
Go
Raw Normal View History

2018-03-01 07:10:04 +00:00
package storeconfig
2017-11-09 16:08:03 +00:00
import (
"encoding/json"
"fmt"
2018-03-05 19:54:04 +00:00
"io/ioutil"
2017-11-21 09:24:03 +00:00
stdlog "log"
2018-03-05 19:54:04 +00:00
"os"
2017-11-09 16:08:03 +00:00
"github.com/abronan/valkeyrie/store"
2017-11-09 16:08:03 +00:00
"github.com/containous/flaeg"
"github.com/containous/staert"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/cluster"
2018-03-01 07:10:04 +00:00
"github.com/containous/traefik/cmd"
2018-03-05 19:54:04 +00:00
"github.com/containous/traefik/log"
2017-11-09 16:08:03 +00:00
)
2018-03-01 07:10:04 +00:00
// NewCmd builds a new StoreConfig command
func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfiguration *cmd.TraefikConfiguration) *flaeg.Command {
2017-11-09 16:08:03 +00:00
return &flaeg.Command{
Name: "storeconfig",
Description: `Store the static traefik configuration into a Key-value stores. Traefik will not start.`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Metadata: map[string]string{
"parseAllSources": "true",
},
}
}
2018-03-01 07:10:04 +00:00
// Run store config in KV
func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) func() error {
2017-11-09 16:08:03 +00:00
return func() error {
if kv == nil {
return fmt.Errorf("error using command storeconfig, no Key-value store defined")
}
2017-11-21 09:24:03 +00:00
fileConfig := traefikConfiguration.GlobalConfiguration.File
if fileConfig != nil {
traefikConfiguration.GlobalConfiguration.File = nil
if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 {
fileConfig.Filename = traefikConfiguration.ConfigFile
}
}
2017-11-09 16:08:03 +00:00
jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration)
if err != nil {
return err
}
2017-11-21 09:24:03 +00:00
stdlog.Printf("Storing configuration: %s\n", jsonConf)
2017-11-09 16:08:03 +00:00
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
if err != nil {
return err
}
2017-11-21 09:24:03 +00:00
if fileConfig != nil {
jsonConf, err = json.Marshal(fileConfig)
if err != nil {
return err
}
stdlog.Printf("Storing file configuration: %s\n", jsonConf)
2017-12-02 18:25:29 +00:00
config, err := fileConfig.BuildConfiguration()
2017-11-21 09:24:03 +00:00
if err != nil {
return err
}
stdlog.Print("Writing config to KV")
err = kv.StoreConfig(config)
if err != nil {
return err
}
}
2018-02-19 00:04:45 +00:00
if traefikConfiguration.GlobalConfiguration.ACME != nil {
2018-03-26 12:12:03 +00:00
account := &acme.Account{}
// Migrate ACME data from file to KV store if needed
if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
2018-03-26 12:12:03 +00:00
account, err = migrateACMEData(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
if err != nil {
return err
}
}
accountInitialized, err := keyExists(kv, traefikConfiguration.GlobalConfiguration.ACME.Storage)
if err != nil && err != store.ErrKeyNotFound {
return err
}
// Check to see if ACME account object is already in kv store
if traefikConfiguration.GlobalConfiguration.ACME.OverrideCertificates || !accountInitialized {
2018-03-26 12:12:03 +00:00
// Store the ACME Account into the KV Store
// Certificates in KV Store will be overridden
meta := cluster.NewMetadata(account)
err = meta.Marshall()
if err != nil {
return err
}
2018-03-26 12:12:03 +00:00
source := staert.KvSource{
Store: kv,
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
}
err = source.StoreConfig(meta)
if err != nil {
return err
}
2018-03-26 12:12:03 +00:00
}
// Force to delete storagefile
return kv.Delete(kv.Prefix + "/acme/storagefile")
2018-03-05 19:54:04 +00:00
}
return nil
}
}
2017-11-21 09:24:03 +00:00
func keyExists(source *staert.KvSource, key string) (bool, error) {
list, err := source.List(key, nil)
if err != nil {
return false, err
}
return len(list) > 0, nil
}
2018-03-05 19:54:04 +00:00
// migrateACMEData allows migrating data from acme.json file to KV store in function of the file format
2018-03-26 12:12:03 +00:00
func migrateACMEData(fileName string) (*acme.Account, error) {
2017-11-21 09:24:03 +00:00
2018-03-05 19:54:04 +00:00
f, err := os.Open(fileName)
if err != nil {
2018-03-26 12:12:03 +00:00
return nil, err
2018-03-05 19:54:04 +00:00
}
defer f.Close()
file, err := ioutil.ReadAll(f)
if err != nil {
2018-03-26 12:12:03 +00:00
return nil, err
2018-03-05 19:54:04 +00:00
}
// Check if the storage file is not empty before to get data
2018-03-26 12:12:03 +00:00
account := &acme.Account{}
2018-03-05 19:54:04 +00:00
if len(file) > 0 {
accountFromNewFormat, err := acme.FromNewToOldFormat(fileName)
if err != nil {
2018-03-26 12:12:03 +00:00
return nil, err
2018-03-05 19:54:04 +00:00
}
if accountFromNewFormat == nil {
// convert ACME json file to KV store (used for backward compatibility)
localStore := acme.NewLocalStore(fileName)
2018-03-05 19:54:04 +00:00
account, err = localStore.Get()
if err != nil {
2018-03-26 12:12:03 +00:00
return nil, err
}
err = account.RemoveAccountV1Values()
if err != nil {
return nil, err
}
2018-03-05 19:54:04 +00:00
} else {
account = accountFromNewFormat
2017-11-09 16:08:03 +00:00
}
2018-03-05 19:54:04 +00:00
} else {
log.Warnf("No data will be imported from the storageFile %q because it is empty.", fileName)
}
err = account.Init()
2018-03-26 12:12:03 +00:00
return account, err
2017-11-09 16:08:03 +00:00
}
2018-03-01 07:10:04 +00:00
// CreateKvSource creates KvSource
2017-11-09 16:08:03 +00:00
// TLS support is enable for Consul and Etcd backends
2018-03-01 07:10:04 +00:00
func CreateKvSource(traefikConfiguration *cmd.TraefikConfiguration) (*staert.KvSource, error) {
2017-11-09 16:08:03 +00:00
var kv *staert.KvSource
var kvStore store.Store
var err error
switch {
case traefikConfiguration.Consul != nil:
kvStore, err = traefikConfiguration.Consul.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Consul.Prefix,
}
case traefikConfiguration.Etcd != nil:
kvStore, err = traefikConfiguration.Etcd.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Etcd.Prefix,
}
case traefikConfiguration.Zookeeper != nil:
kvStore, err = traefikConfiguration.Zookeeper.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Zookeeper.Prefix,
}
case traefikConfiguration.Boltdb != nil:
kvStore, err = traefikConfiguration.Boltdb.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Boltdb.Prefix,
}
}
return kv, err
}