Remove old global config and use new static config

This commit is contained in:
SALLEYRON Julien 2018-11-27 17:42:04 +01:00 committed by Traefiker Bot
parent c39d21c178
commit 5d91c7e15c
114 changed files with 2485 additions and 3646 deletions

View file

@ -5,36 +5,19 @@ import (
"github.com/containous/traefik/anonymize"
"github.com/containous/traefik/cmd"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/provider/file"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/config/static"
"github.com/stretchr/testify/assert"
)
func Test_createReport(t *testing.T) {
traefikConfiguration := &cmd.TraefikConfiguration{
ConfigFile: "FOO",
GlobalConfiguration: configuration.GlobalConfiguration{
EntryPoints: configuration.EntryPoints{
"goo": &configuration.EntryPoint{
Configuration: static.Configuration{
EntryPoints: static.EntryPoints{
"goo": &static.EntryPoint{
Address: "hoo.bar",
Auth: &types.Auth{
Basic: &types.Basic{
UsersFile: "foo Basic UsersFile",
Users: types.Users{"foo Basic Users 1", "foo Basic Users 2", "foo Basic Users 3"},
},
Digest: &types.Digest{
UsersFile: "foo Digest UsersFile",
Users: types.Users{"foo Digest Users 1", "foo Digest Users 2", "foo Digest Users 3"},
},
},
},
},
File: &file.Provider{
Directory: "BAR",
},
RootCAs: tls.FilesOrContents{"fllf"},
},
}
@ -42,26 +25,21 @@ func Test_createReport(t *testing.T) {
assert.NoError(t, err, report)
// exported anonymous configuration
assert.NotContains(t, "web Basic Users ", report)
assert.NotContains(t, "foo Digest Users ", report)
assert.NotContains(t, "hoo.bar", report)
}
func Test_anonymize_traefikConfiguration(t *testing.T) {
traefikConfiguration := &cmd.TraefikConfiguration{
ConfigFile: "FOO",
GlobalConfiguration: configuration.GlobalConfiguration{
EntryPoints: configuration.EntryPoints{
"goo": &configuration.EntryPoint{
Configuration: static.Configuration{
EntryPoints: static.EntryPoints{
"goo": &static.EntryPoint{
Address: "hoo.bar",
},
},
File: &file.Provider{
Directory: "BAR",
},
},
}
_, err := anonymize.Do(traefikConfiguration, true)
assert.NoError(t, err)
assert.Equal(t, "hoo.bar", traefikConfiguration.GlobalConfiguration.EntryPoints["goo"].Address)
assert.Equal(t, "hoo.bar", traefikConfiguration.Configuration.EntryPoints["goo"].Address)
}

View file

@ -4,14 +4,9 @@ import (
"time"
"github.com/containous/flaeg/parse"
"github.com/containous/traefik/old/api"
"github.com/containous/traefik/config/static"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/middlewares/accesslog"
"github.com/containous/traefik/old/middlewares/tracing"
"github.com/containous/traefik/old/middlewares/tracing/datadog"
"github.com/containous/traefik/old/middlewares/tracing/jaeger"
"github.com/containous/traefik/old/middlewares/tracing/zipkin"
"github.com/containous/traefik/old/ping"
"github.com/containous/traefik/old/provider/boltdb"
"github.com/containous/traefik/old/provider/consul"
"github.com/containous/traefik/old/provider/consulcatalog"
@ -20,129 +15,53 @@ import (
"github.com/containous/traefik/old/provider/ecs"
"github.com/containous/traefik/old/provider/etcd"
"github.com/containous/traefik/old/provider/eureka"
"github.com/containous/traefik/old/provider/file"
"github.com/containous/traefik/old/provider/kubernetes"
"github.com/containous/traefik/old/provider/marathon"
"github.com/containous/traefik/old/provider/mesos"
"github.com/containous/traefik/old/provider/rancher"
"github.com/containous/traefik/old/provider/rest"
"github.com/containous/traefik/old/provider/zk"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/ping"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/tracing/datadog"
"github.com/containous/traefik/tracing/jaeger"
"github.com/containous/traefik/tracing/zipkin"
"github.com/containous/traefik/types"
)
// TraefikConfiguration holds GlobalConfiguration and other stuff
type TraefikConfiguration struct {
configuration.GlobalConfiguration `mapstructure:",squash" export:"true"`
ConfigFile string `short:"c" description:"Configuration file to use (TOML)." export:"true"`
static.Configuration `mapstructure:",squash" export:"true"`
ConfigFile string `short:"c" description:"Configuration file to use (TOML)." export:"true"`
}
// NewTraefikConfiguration creates a TraefikConfiguration with default values
func NewTraefikConfiguration() *TraefikConfiguration {
return &TraefikConfiguration{
Configuration: static.Configuration{
Global: &static.Global{
CheckNewVersion: true,
SendAnonymousUsage: false,
},
EntryPoints: make(static.EntryPoints),
Providers: &static.Providers{
ProvidersThrottleDuration: parse.Duration(2 * time.Second),
},
ServersTransport: &static.ServersTransport{
MaxIdleConnsPerHost: 200,
},
},
ConfigFile: "",
}
}
// NewTraefikDefaultPointersConfiguration creates a TraefikConfiguration with pointers default values
func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
// default Docker
var defaultDocker docker.Provider
defaultDocker.Watch = true
defaultDocker.ExposedByDefault = true
defaultDocker.Endpoint = "unix:///var/run/docker.sock"
defaultDocker.SwarmMode = false
// default File
var defaultFile file.Provider
defaultFile.Watch = true
defaultFile.Filename = "" // needs equivalent to viper.ConfigFileUsed()
// default Rest
var defaultRest rest.Provider
defaultRest.EntryPoint = configuration.DefaultInternalEntryPointName
// default Marathon
var defaultMarathon marathon.Provider
defaultMarathon.Watch = true
defaultMarathon.Endpoint = "http://127.0.0.1:8080"
defaultMarathon.ExposedByDefault = true
defaultMarathon.Constraints = types.Constraints{}
defaultMarathon.DialerTimeout = parse.Duration(5 * time.Second)
defaultMarathon.ResponseHeaderTimeout = parse.Duration(60 * time.Second)
defaultMarathon.TLSHandshakeTimeout = parse.Duration(5 * time.Second)
defaultMarathon.KeepAlive = parse.Duration(10 * time.Second)
// default Consul
var defaultConsul consul.Provider
defaultConsul.Watch = true
defaultConsul.Endpoint = "127.0.0.1:8500"
defaultConsul.Prefix = "traefik"
defaultConsul.Constraints = types.Constraints{}
// default CatalogProvider
var defaultConsulCatalog consulcatalog.Provider
defaultConsulCatalog.Endpoint = "127.0.0.1:8500"
defaultConsulCatalog.ExposedByDefault = true
defaultConsulCatalog.Constraints = types.Constraints{}
defaultConsulCatalog.Prefix = "traefik"
defaultConsulCatalog.FrontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
defaultConsulCatalog.Stale = false
// default Etcd
var defaultEtcd etcd.Provider
defaultEtcd.Watch = true
defaultEtcd.Endpoint = "127.0.0.1:2379"
defaultEtcd.Prefix = "/traefik"
defaultEtcd.Constraints = types.Constraints{}
// default Zookeeper
var defaultZookeeper zk.Provider
defaultZookeeper.Watch = true
defaultZookeeper.Endpoint = "127.0.0.1:2181"
defaultZookeeper.Prefix = "traefik"
defaultZookeeper.Constraints = types.Constraints{}
// default Boltdb
var defaultBoltDb boltdb.Provider
defaultBoltDb.Watch = true
defaultBoltDb.Endpoint = "127.0.0.1:4001"
defaultBoltDb.Prefix = "/traefik"
defaultBoltDb.Constraints = types.Constraints{}
// default Kubernetes
var defaultKubernetes kubernetes.Provider
defaultKubernetes.Watch = true
defaultKubernetes.Constraints = types.Constraints{}
// default Mesos
var defaultMesos mesos.Provider
defaultMesos.Watch = true
defaultMesos.Endpoint = "http://127.0.0.1:5050"
defaultMesos.ExposedByDefault = true
defaultMesos.Constraints = types.Constraints{}
defaultMesos.RefreshSeconds = 30
defaultMesos.ZkDetectionTimeout = 30
defaultMesos.StateTimeoutSecond = 30
// default ECS
var defaultECS ecs.Provider
defaultECS.Watch = true
defaultECS.ExposedByDefault = true
defaultECS.AutoDiscoverClusters = false
defaultECS.Clusters = ecs.Clusters{"default"}
defaultECS.RefreshSeconds = 15
defaultECS.Constraints = types.Constraints{}
// default Rancher
var defaultRancher rancher.Provider
defaultRancher.Watch = true
defaultRancher.ExposedByDefault = true
defaultRancher.RefreshSeconds = 15
// default DynamoDB
var defaultDynamoDB dynamodb.Provider
defaultDynamoDB.Constraints = types.Constraints{}
defaultDynamoDB.RefreshSeconds = 15
defaultDynamoDB.TableName = "traefik"
defaultDynamoDB.Watch = true
// default Eureka
var defaultEureka eureka.Provider
defaultEureka.RefreshSeconds = parse.Duration(30 * time.Second)
// default Ping
var defaultPing = ping.Handler{
EntryPoint: "traefik",
@ -167,24 +86,8 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
},
}
// default HealthCheckConfig
healthCheck := configuration.HealthCheckConfig{
Interval: parse.Duration(configuration.DefaultHealthCheckInterval),
Timeout: parse.Duration(configuration.DefaultHealthCheckTimeout),
}
// default RespondingTimeouts
respondingTimeouts := configuration.RespondingTimeouts{
IdleTimeout: parse.Duration(configuration.DefaultIdleTimeout),
}
// default ForwardingTimeouts
forwardingTimeouts := configuration.ForwardingTimeouts{
DialTimeout: parse.Duration(configuration.DefaultDialTimeout),
}
// default Tracing
defaultTracing := tracing.Tracing{
defaultTracing := static.Tracing{
Backend: "jaeger",
ServiceName: "traefik",
SpanNameLimit: 0,
@ -210,13 +113,8 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
},
}
// default LifeCycle
defaultLifeCycle := configuration.LifeCycle{
GraceTimeOut: parse.Duration(configuration.DefaultGraceTimeout),
}
// default ApiConfiguration
defaultAPI := api.Handler{
defaultAPI := static.API{
EntryPoint: "traefik",
Dashboard: true,
}
@ -245,65 +143,129 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
},
}
defaultResolver := configuration.HostResolverConfig{
defaultResolver := static.HostResolverConfig{
CnameFlattening: false,
ResolvConfig: "/etc/resolv.conf",
ResolvDepth: 5,
}
defaultConfiguration := configuration.GlobalConfiguration{
Docker: &defaultDocker,
File: &defaultFile,
Rest: &defaultRest,
Marathon: &defaultMarathon,
Consul: &defaultConsul,
ConsulCatalog: &defaultConsulCatalog,
Etcd: &defaultEtcd,
Zookeeper: &defaultZookeeper,
Boltdb: &defaultBoltDb,
Kubernetes: &defaultKubernetes,
Mesos: &defaultMesos,
ECS: &defaultECS,
Rancher: &defaultRancher,
Eureka: &defaultEureka,
DynamoDB: &defaultDynamoDB,
Retry: &configuration.Retry{},
HealthCheck: &healthCheck,
RespondingTimeouts: &respondingTimeouts,
ForwardingTimeouts: &forwardingTimeouts,
TraefikLog: &defaultTraefikLog,
AccessLog: &defaultAccessLog,
LifeCycle: &defaultLifeCycle,
Ping: &defaultPing,
API: &defaultAPI,
Metrics: &defaultMetrics,
Tracing: &defaultTracing,
HostResolver: &defaultResolver,
var defaultDocker docker.Provider
defaultDocker.Watch = true
defaultDocker.ExposedByDefault = true
defaultDocker.Endpoint = "unix:///var/run/docker.sock"
defaultDocker.SwarmMode = false
// default Rest
var defaultRest rest.Provider
defaultRest.EntryPoint = configuration.DefaultInternalEntryPointName
// default Marathon
var defaultMarathon marathon.Provider
defaultMarathon.Watch = true
defaultMarathon.Endpoint = "http://127.0.0.1:8080"
defaultMarathon.ExposedByDefault = true
defaultMarathon.DialerTimeout = parse.Duration(5 * time.Second)
defaultMarathon.ResponseHeaderTimeout = parse.Duration(60 * time.Second)
defaultMarathon.TLSHandshakeTimeout = parse.Duration(5 * time.Second)
defaultMarathon.KeepAlive = parse.Duration(10 * time.Second)
// default Consul
var defaultConsul consul.Provider
defaultConsul.Watch = true
defaultConsul.Endpoint = "127.0.0.1:8500"
defaultConsul.Prefix = "traefik"
// default CatalogProvider
var defaultConsulCatalog consulcatalog.Provider
defaultConsulCatalog.Endpoint = "127.0.0.1:8500"
defaultConsulCatalog.ExposedByDefault = true
defaultConsulCatalog.Prefix = "traefik"
defaultConsulCatalog.FrontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
defaultConsulCatalog.Stale = false
// default Etcd
var defaultEtcd etcd.Provider
defaultEtcd.Watch = true
defaultEtcd.Endpoint = "127.0.0.1:2379"
defaultEtcd.Prefix = "/traefik"
// default Zookeeper
var defaultZookeeper zk.Provider
defaultZookeeper.Watch = true
defaultZookeeper.Endpoint = "127.0.0.1:2181"
defaultZookeeper.Prefix = "traefik"
// default Boltdb
var defaultBoltDb boltdb.Provider
defaultBoltDb.Watch = true
defaultBoltDb.Endpoint = "127.0.0.1:4001"
defaultBoltDb.Prefix = "/traefik"
// default Kubernetes
var defaultKubernetes kubernetes.Provider
defaultKubernetes.Watch = true
// default Mesos
var defaultMesos mesos.Provider
defaultMesos.Watch = true
defaultMesos.Endpoint = "http://127.0.0.1:5050"
defaultMesos.ExposedByDefault = true
defaultMesos.RefreshSeconds = 30
defaultMesos.ZkDetectionTimeout = 30
defaultMesos.StateTimeoutSecond = 30
// default ECS
var defaultECS ecs.Provider
defaultECS.Watch = true
defaultECS.ExposedByDefault = true
defaultECS.AutoDiscoverClusters = false
defaultECS.Clusters = ecs.Clusters{"default"}
defaultECS.RefreshSeconds = 15
// default Rancher
var defaultRancher rancher.Provider
defaultRancher.Watch = true
defaultRancher.ExposedByDefault = true
defaultRancher.RefreshSeconds = 15
// default DynamoDB
var defaultDynamoDB dynamodb.Provider
defaultDynamoDB.RefreshSeconds = 15
defaultDynamoDB.TableName = "traefik"
defaultDynamoDB.Watch = true
// default Eureka
var defaultEureka eureka.Provider
defaultEureka.RefreshSeconds = parse.Duration(30 * time.Second)
defaultProviders := static.Providers{
File: &defaultFile,
Docker: &defaultDocker,
Rest: &defaultRest,
Marathon: &defaultMarathon,
Consul: &defaultConsul,
ConsulCatalog: &defaultConsulCatalog,
Etcd: &defaultEtcd,
Zookeeper: &defaultZookeeper,
Boltdb: &defaultBoltDb,
Kubernetes: &defaultKubernetes,
Mesos: &defaultMesos,
ECS: &defaultECS,
Rancher: &defaultRancher,
Eureka: &defaultEureka,
DynamoDB: &defaultDynamoDB,
}
return &TraefikConfiguration{
GlobalConfiguration: defaultConfiguration,
}
}
// NewTraefikConfiguration creates a TraefikConfiguration with default values
func NewTraefikConfiguration() *TraefikConfiguration {
return &TraefikConfiguration{
GlobalConfiguration: configuration.GlobalConfiguration{
EntryPoints: map[string]*configuration.EntryPoint{},
Constraints: types.Constraints{},
DefaultEntryPoints: []string{"http"},
ProvidersThrottleDuration: parse.Duration(2 * time.Second),
MaxIdleConnsPerHost: 200,
HealthCheck: &configuration.HealthCheckConfig{
Interval: parse.Duration(configuration.DefaultHealthCheckInterval),
Timeout: parse.Duration(configuration.DefaultHealthCheckTimeout),
},
LifeCycle: &configuration.LifeCycle{
GraceTimeOut: parse.Duration(configuration.DefaultGraceTimeout),
},
CheckNewVersion: true,
Configuration: static.Configuration{
Providers: &defaultProviders,
Log: &defaultTraefikLog,
AccessLog: &defaultAccessLog,
Ping: &defaultPing,
API: &defaultAPI,
Metrics: &defaultMetrics,
Tracing: &defaultTracing,
HostResolver: &defaultResolver,
},
ConfigFile: "",
}
}

View file

@ -10,7 +10,7 @@ import (
"github.com/containous/flaeg"
"github.com/containous/traefik/cmd"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/config/static"
)
// NewCmd builds a new HealthCheck command
@ -29,9 +29,9 @@ func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfi
func runCmd(traefikConfiguration *cmd.TraefikConfiguration) func() error {
return func() error {
traefikConfiguration.GlobalConfiguration.SetEffectiveConfiguration(traefikConfiguration.ConfigFile)
traefikConfiguration.Configuration.SetEffectiveConfiguration(traefikConfiguration.ConfigFile)
resp, errPing := Do(traefikConfiguration.GlobalConfiguration)
resp, errPing := Do(traefikConfiguration.Configuration)
if errPing != nil {
fmt.Printf("Error calling healthcheck: %s\n", errPing)
os.Exit(1)
@ -47,17 +47,18 @@ func runCmd(traefikConfiguration *cmd.TraefikConfiguration) func() error {
}
// Do try to do a healthcheck
func Do(globalConfiguration configuration.GlobalConfiguration) (*http.Response, error) {
if globalConfiguration.Ping == nil {
func Do(staticConfiguration static.Configuration) (*http.Response, error) {
if staticConfiguration.Ping == nil {
return nil, errors.New("please enable `ping` to use health check")
}
pingEntryPoint, ok := globalConfiguration.EntryPoints[globalConfiguration.Ping.EntryPoint]
pingEntryPoint, ok := staticConfiguration.EntryPoints[staticConfiguration.Ping.EntryPoint]
if !ok {
return nil, errors.New("missing `ping` entrypoint")
}
client := &http.Client{Timeout: 5 * time.Second}
protocol := "http"
if pingEntryPoint.TLS != nil {
protocol = "https"
tr := &http.Transport{
@ -65,6 +66,7 @@ func Do(globalConfiguration configuration.GlobalConfiguration) (*http.Response,
}
client.Transport = tr
}
path := "/"
return client.Head(protocol + "://" + pingEntryPoint.Address + path + "ping")

View file

@ -36,21 +36,21 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
return fmt.Errorf("error using command storeconfig, no Key-value store defined")
}
fileConfig := traefikConfiguration.GlobalConfiguration.File
fileConfig := traefikConfiguration.Providers.File
if fileConfig != nil {
traefikConfiguration.GlobalConfiguration.File = nil
traefikConfiguration.Providers.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.Configuration)
if err != nil {
return err
}
stdlog.Printf("Storing configuration: %s\n", jsonConf)
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
err = kv.StoreConfig(traefikConfiguration.Configuration)
if err != nil {
return err
}
@ -74,24 +74,24 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
}
}
if traefikConfiguration.GlobalConfiguration.ACME != nil {
if traefikConfiguration.Configuration.ACME != nil {
account := &acme.Account{}
// Migrate ACME data from file to KV store if needed
if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
account, err = migrateACMEData(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
if len(traefikConfiguration.Configuration.ACME.StorageFile) > 0 {
account, err = migrateACMEData(traefikConfiguration.Configuration.ACME.StorageFile)
if err != nil {
return err
}
}
accountInitialized, err := keyExists(kv, traefikConfiguration.GlobalConfiguration.ACME.Storage)
accountInitialized, err := keyExists(kv, traefikConfiguration.Configuration.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 {
if traefikConfiguration.Configuration.ACME.OverrideCertificates || !accountInitialized {
// Store the ACME Account into the KV Store
// Certificates in KV Store will be overridden
@ -103,7 +103,7 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
source := staert.KvSource{
Store: kv,
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
Prefix: traefikConfiguration.Configuration.ACME.Storage,
}
err = source.StoreConfig(meta)
@ -182,29 +182,29 @@ func CreateKvSource(traefikConfiguration *cmd.TraefikConfiguration) (*staert.KvS
var err error
switch {
case traefikConfiguration.Consul != nil:
kvStore, err = traefikConfiguration.Consul.CreateStore()
case traefikConfiguration.Providers.Consul != nil:
kvStore, err = traefikConfiguration.Providers.Consul.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Consul.Prefix,
Prefix: traefikConfiguration.Providers.Consul.Prefix,
}
case traefikConfiguration.Etcd != nil:
kvStore, err = traefikConfiguration.Etcd.CreateStore()
case traefikConfiguration.Providers.Etcd != nil:
kvStore, err = traefikConfiguration.Providers.Etcd.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Etcd.Prefix,
Prefix: traefikConfiguration.Providers.Etcd.Prefix,
}
case traefikConfiguration.Zookeeper != nil:
kvStore, err = traefikConfiguration.Zookeeper.CreateStore()
case traefikConfiguration.Providers.Zookeeper != nil:
kvStore, err = traefikConfiguration.Providers.Zookeeper.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Zookeeper.Prefix,
Prefix: traefikConfiguration.Providers.Zookeeper.Prefix,
}
case traefikConfiguration.Boltdb != nil:
kvStore, err = traefikConfiguration.Boltdb.CreateStore()
case traefikConfiguration.Providers.Boltdb != nil:
kvStore, err = traefikConfiguration.Providers.Boltdb.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Boltdb.Prefix,
Prefix: traefikConfiguration.Providers.Boltdb.Prefix,
}
}
return kv, err

View file

@ -3,6 +3,7 @@ package main
import (
"context"
"encoding/json"
"fmt"
fmtlog "log"
"net/http"
"os"
@ -25,16 +26,15 @@ import (
"github.com/containous/traefik/config/static"
"github.com/containous/traefik/job"
"github.com/containous/traefik/log"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/provider/ecs"
"github.com/containous/traefik/old/provider/kubernetes"
"github.com/containous/traefik/old/types"
oldtypes "github.com/containous/traefik/old/types"
"github.com/containous/traefik/provider/aggregator"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/server"
"github.com/containous/traefik/server/router"
"github.com/containous/traefik/server/uuid"
traefiktls "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/coreos/go-systemd/daemon"
"github.com/elazarl/go-bindata-assetfs"
@ -43,6 +43,44 @@ import (
"github.com/vulcand/oxy/roundrobin"
)
// sliceOfStrings is the parser for []string
type sliceOfStrings []string
// String is the method to format the flag's value, part of the flag.Value interface.
// The String method's output will be used in diagnostics.
func (s *sliceOfStrings) String() string {
return strings.Join(*s, ",")
}
// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it.
func (s *sliceOfStrings) Set(value string) error {
strings := strings.Split(value, ",")
if len(strings) == 0 {
return fmt.Errorf("bad []string format: %s", value)
}
for _, entrypoint := range strings {
*s = append(*s, entrypoint)
}
return nil
}
// Get return the []string
func (s *sliceOfStrings) Get() interface{} {
return *s
}
// SetValue sets the []string with val
func (s *sliceOfStrings) SetValue(val interface{}) {
*s = val.([]string)
}
// Type is type of the struct
func (s *sliceOfStrings) Type() string {
return "sliceOfStrings"
}
func main() {
// traefik config inits
traefikConfiguration := cmd.NewTraefikConfiguration()
@ -56,7 +94,7 @@ Complete documentation is available at https://traefik.io`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: func() error {
runCmd(&traefikConfiguration.GlobalConfiguration, traefikConfiguration.ConfigFile)
runCmd(&traefikConfiguration.Configuration, traefikConfiguration.ConfigFile)
return nil
},
}
@ -67,8 +105,9 @@ Complete documentation is available at https://traefik.io`,
// init flaeg source
f := flaeg.New(traefikCmd, os.Args[1:])
// add custom parsers
f.AddParser(reflect.TypeOf(configuration.EntryPoints{}), &configuration.EntryPoints{})
f.AddParser(reflect.TypeOf(configuration.DefaultEntryPoints{}), &configuration.DefaultEntryPoints{})
f.AddParser(reflect.TypeOf(static.EntryPoints{}), &static.EntryPoints{})
f.AddParser(reflect.SliceOf(reflect.TypeOf("")), &sliceOfStrings{})
f.AddParser(reflect.TypeOf(traefiktls.FilesOrContents{}), &traefiktls.FilesOrContents{})
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
@ -76,10 +115,16 @@ Complete documentation is available at https://traefik.io`,
f.AddParser(reflect.TypeOf([]types.Domain{}), &types.Domains{})
f.AddParser(reflect.TypeOf(types.DNSResolvers{}), &types.DNSResolvers{})
f.AddParser(reflect.TypeOf(types.Buckets{}), &types.Buckets{})
f.AddParser(reflect.TypeOf(types.StatusCodes{}), &types.StatusCodes{})
f.AddParser(reflect.TypeOf(types.FieldNames{}), &types.FieldNames{})
f.AddParser(reflect.TypeOf(types.FieldHeaderNames{}), &types.FieldHeaderNames{})
// FIXME Remove with ACME
f.AddParser(reflect.TypeOf([]oldtypes.Domain{}), &oldtypes.Domains{})
// FIXME Remove with old providers
f.AddParser(reflect.TypeOf(oldtypes.Constraints{}), &oldtypes.Constraints{})
// add commands
f.AddCommand(cmdVersion.NewCmd())
f.AddCommand(bug.NewCmd(traefikConfiguration, traefikPointersConfiguration))
@ -124,19 +169,13 @@ Complete documentation is available at https://traefik.io`,
// if a KV Store is enable and no sub-command called in args
if kv != nil && usedCmd == traefikCmd {
if traefikConfiguration.Cluster == nil {
traefikConfiguration.Cluster = &types.Cluster{Node: uuid.Get()}
}
if traefikConfiguration.Cluster.Store == nil {
traefikConfiguration.Cluster.Store = &types.Store{Prefix: kv.Prefix, Store: kv.Store}
}
s.AddSource(kv)
operation := func() error {
_, err := s.LoadConfig()
return err
}
notify := func(err error, time time.Duration) {
log.Errorf("Load config error: %+v, retrying in %s", err, time)
log.WithoutContext().Errorf("Load config error: %+v, retrying in %s", err, time)
}
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
if err != nil {
@ -153,84 +192,85 @@ Complete documentation is available at https://traefik.io`,
os.Exit(0)
}
func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile string) {
configureLogging(globalConfiguration)
func runCmd(staticConfiguration *static.Configuration, configFile string) {
configureLogging(staticConfiguration)
if len(configFile) > 0 {
log.Infof("Using TOML configuration file %s", configFile)
log.WithoutContext().Infof("Using TOML configuration file %s", configFile)
}
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
if err := roundrobin.SetDefaultWeight(0); err != nil {
log.Error(err)
log.WithoutContext().Errorf("Could not set roundrobin default weight: %v", err)
}
globalConfiguration.SetEffectiveConfiguration(configFile)
globalConfiguration.ValidateConfiguration()
staticConfiguration.SetEffectiveConfiguration(configFile)
staticConfiguration.ValidateConfiguration()
log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
log.WithoutContext().Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
jsonConf, err := json.Marshal(globalConfiguration)
jsonConf, err := json.Marshal(staticConfiguration)
if err != nil {
log.Error(err)
log.Debugf("Global configuration loaded [struct] %#v", globalConfiguration)
log.WithoutContext().Errorf("Could not marshal static configuration: %v", err)
log.WithoutContext().Debugf("Static configuration loaded [struct] %#v", staticConfiguration)
} else {
log.Debugf("Global configuration loaded %s", string(jsonConf))
log.WithoutContext().Debugf("Static configuration loaded %s", string(jsonConf))
}
if globalConfiguration.API != nil && globalConfiguration.API.Dashboard {
globalConfiguration.API.DashboardAssets = &assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"}
if staticConfiguration.API != nil && staticConfiguration.API.Dashboard {
staticConfiguration.API.DashboardAssets = &assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"}
}
if globalConfiguration.CheckNewVersion {
if staticConfiguration.Global.CheckNewVersion {
checkNewVersion()
}
stats(globalConfiguration)
stats(staticConfiguration)
providerAggregator := aggregator.NewProviderAggregator(static.ConvertStaticConf(*globalConfiguration))
providerAggregator := aggregator.NewProviderAggregator(*staticConfiguration.Providers)
acmeProvider, err := globalConfiguration.InitACMEProvider()
acmeProvider, err := staticConfiguration.InitACMEProvider()
if err != nil {
log.Errorf("Unable to initialize ACME provider: %v", err)
log.WithoutContext().Errorf("Unable to initialize ACME provider: %v", err)
} else if acmeProvider != nil {
if err := providerAggregator.AddProvider(acmeProvider); err != nil {
log.Errorf("Unable to add ACME provider to the providers list: %v", err)
log.WithoutContext().Errorf("Unable to add ACME provider to the providers list: %v", err)
acmeProvider = nil
}
}
entryPoints := map[string]server.EntryPoint{}
staticConf := static.ConvertStaticConf(*globalConfiguration)
for entryPointName, config := range globalConfiguration.EntryPoints {
factory := router.NewRouteAppenderFactory(staticConf, entryPointName, acmeProvider)
entryPoint := server.EntryPoint{
RouteAppenderFactory: factory,
Configuration: config,
serverEntryPoints := make(server.EntryPoints)
for entryPointName, config := range staticConfiguration.EntryPoints {
ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName))
logger := log.FromContext(ctx)
serverEntryPoint, err := server.NewEntryPoint(ctx, config)
if err != nil {
logger.Errorf("Error while building entryPoint: %v", err)
continue
}
if acmeProvider != nil {
serverEntryPoint.RouteAppenderFactory = router.NewRouteAppenderFactory(*staticConfiguration, entryPointName, acmeProvider)
if acmeProvider != nil && entryPointName == acmeProvider.EntryPoint {
logger.Debugf("Setting Acme Certificate store from Entrypoint")
acmeProvider.SetCertificateStore(serverEntryPoint.Certs)
if acmeProvider.OnDemand {
serverEntryPoint.OnDemandListener = acmeProvider.ListenRequest
}
// TLS ALPN 01
if acmeProvider.TLSChallenge != nil && acmeProvider.HTTPChallenge == nil && acmeProvider.DNSChallenge == nil {
entryPoint.TLSALPNGetter = acmeProvider.GetTLSALPNCertificate
}
if acmeProvider.OnDemand && entryPointName == acmeProvider.EntryPoint {
entryPoint.OnDemandListener = acmeProvider.ListenRequest
}
if entryPointName == acmeProvider.EntryPoint {
entryPoint.CertificateStore = traefiktls.NewCertificateStore()
acmeProvider.SetCertificateStore(entryPoint.CertificateStore)
log.Debugf("Setting Acme Certificate store from Entrypoint: %s", entryPointName)
serverEntryPoint.TLSALPNGetter = acmeProvider.GetTLSALPNCertificate
}
}
entryPoints[entryPointName] = entryPoint
serverEntryPoints[entryPointName] = serverEntryPoint
}
svr := server.NewServer(*globalConfiguration, providerAggregator, entryPoints)
svr := server.NewServer(*staticConfiguration, providerAggregator, serverEntryPoints)
if acmeProvider != nil && acmeProvider.OnHostRule {
acmeProvider.SetConfigListenerChan(make(chan config.Configuration))
@ -238,46 +278,46 @@ func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile s
}
ctx := cmd.ContextWithSignal(context.Background())
if staticConf.Ping != nil {
staticConf.Ping.WithContext(ctx)
if staticConfiguration.Ping != nil {
staticConfiguration.Ping.WithContext(ctx)
}
svr.StartWithContext(ctx)
svr.Start(ctx)
defer svr.Close()
sent, err := daemon.SdNotify(false, "READY=1")
if !sent && err != nil {
log.Error("Fail to notify", err)
log.WithoutContext().Errorf("Failed to notify: %v", err)
}
t, err := daemon.SdWatchdogEnabled(false)
if err != nil {
log.Error("Problem with watchdog", err)
log.WithoutContext().Errorf("Could not enable Watchdog: %v", err)
} else if t != 0 {
// Send a ping each half time given
t = t / 2
log.Info("Watchdog activated with timer each ", t)
log.WithoutContext().Infof("Watchdog activated with timer duration %s", t)
safe.Go(func() {
tick := time.Tick(t)
for range tick {
_, errHealthCheck := healthcheck.Do(*globalConfiguration)
if globalConfiguration.Ping == nil || errHealthCheck == nil {
_, errHealthCheck := healthcheck.Do(*staticConfiguration)
if staticConfiguration.Ping == nil || errHealthCheck == nil {
if ok, _ := daemon.SdNotify(false, "WATCHDOG=1"); !ok {
log.Error("Fail to tick watchdog")
log.WithoutContext().Error("Fail to tick watchdog")
}
} else {
log.Error(errHealthCheck)
log.WithoutContext().Error(errHealthCheck)
}
}
})
}
svr.Wait()
log.Info("Shutting down")
log.WithoutContext().Info("Shutting down")
logrus.Exit(0)
}
func configureLogging(globalConfiguration *configuration.GlobalConfiguration) {
func configureLogging(staticConfiguration *static.Configuration) {
// configure default log flags
fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags)
@ -285,27 +325,30 @@ func configureLogging(globalConfiguration *configuration.GlobalConfiguration) {
// an explicitly defined log level always has precedence. if none is
// given and debug mode is disabled, the default is ERROR, and DEBUG
// otherwise.
levelStr := strings.ToLower(globalConfiguration.LogLevel)
var levelStr string
if staticConfiguration.Log != nil {
levelStr = strings.ToLower(staticConfiguration.Log.LogLevel)
}
if levelStr == "" {
levelStr = "error"
if globalConfiguration.Debug {
if staticConfiguration.Global.Debug {
levelStr = "debug"
}
}
level, err := logrus.ParseLevel(levelStr)
if err != nil {
log.Error("Error getting level", err)
log.WithoutContext().Errorf("Error getting level: %v", err)
}
log.SetLevel(level)
var logFile string
if globalConfiguration.TraefikLog != nil && len(globalConfiguration.TraefikLog.FilePath) > 0 {
logFile = globalConfiguration.TraefikLog.FilePath
if staticConfiguration.Log != nil && len(staticConfiguration.Log.FilePath) > 0 {
logFile = staticConfiguration.Log.FilePath
}
// configure log format
var formatter logrus.Formatter
if globalConfiguration.TraefikLog != nil && globalConfiguration.TraefikLog.Format == "json" {
if staticConfiguration.Log != nil && staticConfiguration.Log.Format == "json" {
formatter = &logrus.JSONFormatter{}
} else {
disableColors := len(logFile) > 0
@ -317,17 +360,17 @@ func configureLogging(globalConfiguration *configuration.GlobalConfiguration) {
dir := filepath.Dir(logFile)
if err := os.MkdirAll(dir, 0755); err != nil {
log.Errorf("Failed to create log path %s: %s", dir, err)
log.WithoutContext().Errorf("Failed to create log path %s: %s", dir, err)
}
err = log.OpenFile(logFile)
logrus.RegisterExitHandler(func() {
if err := log.CloseFile(); err != nil {
log.Error("Error closing log", err)
log.WithoutContext().Errorf("Error while closing log: %v", err)
}
})
if err != nil {
log.Error("Error opening file", err)
log.WithoutContext().Errorf("Error while opening log file %s: %v", logFile, err)
}
}
}
@ -341,17 +384,17 @@ func checkNewVersion() {
})
}
func stats(globalConfiguration *configuration.GlobalConfiguration) {
if globalConfiguration.SendAnonymousUsage {
log.Info(`
func stats(staticConfiguration *static.Configuration) {
if staticConfiguration.Global.SendAnonymousUsage {
log.WithoutContext().Info(`
Stats collection is enabled.
Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.
Help us improve Traefik by leaving this feature on :)
More details on: https://docs.traefik.io/basics/#collected-data
`)
collect(globalConfiguration)
collect(staticConfiguration)
} else {
log.Info(`
log.WithoutContext().Info(`
Stats collection is disabled.
Help us improve Traefik by turning this feature on :)
More details on: https://docs.traefik.io/basics/#collected-data
@ -359,12 +402,12 @@ More details on: https://docs.traefik.io/basics/#collected-data
}
}
func collect(globalConfiguration *configuration.GlobalConfiguration) {
func collect(staticConfiguration *static.Configuration) {
ticker := time.Tick(24 * time.Hour)
safe.Go(func() {
for time.Sleep(10 * time.Minute); ; <-ticker {
if err := collector.Collect(globalConfiguration); err != nil {
log.Debug(err)
if err := collector.Collect(staticConfiguration); err != nil {
log.WithoutContext().Debug(err)
}
}
})