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

@ -1,6 +1,7 @@
package acme package acme
import ( import (
"context"
"crypto" "crypto"
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
@ -15,8 +16,8 @@ import (
"time" "time"
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
acmeprovider "github.com/containous/traefik/old/provider/acme" acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/old/types" "github.com/containous/traefik/types"
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
) )
@ -72,7 +73,7 @@ func (a *Account) Init() error {
// NewAccount creates an account // NewAccount creates an account
func NewAccount(email string, certs []*DomainsCertificate, keyTypeValue string) (*Account, error) { func NewAccount(email string, certs []*DomainsCertificate, keyTypeValue string) (*Account, error) {
keyType := acmeprovider.GetKeyType(keyTypeValue) keyType := acmeprovider.GetKeyType(context.Background(), keyTypeValue)
// Create a user. New accounts need an email and private key to start // Create a user. New accounts need an email and private key to start
privateKey, err := rsa.GenerateKey(rand.Reader, 4096) privateKey, err := rsa.GenerateKey(rand.Reader, 4096)

View file

@ -22,9 +22,9 @@ import (
"github.com/containous/staert" "github.com/containous/staert"
"github.com/containous/traefik/cluster" "github.com/containous/traefik/cluster"
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
acmeprovider "github.com/containous/traefik/old/provider/acme" acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/safe" "github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version" "github.com/containous/traefik/version"
"github.com/eapache/channels" "github.com/eapache/channels"
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
@ -208,7 +208,7 @@ func (a *ACME) leadershipListener(elected bool) error {
needRegister = true needRegister = true
} else if len(account.KeyType) == 0 { } else if len(account.KeyType) == 0 {
// Set the KeyType if not already defined in the account // Set the KeyType if not already defined in the account
account.KeyType = acmeprovider.GetKeyType(a.KeyType) account.KeyType = acmeprovider.GetKeyType(context.Background(), a.KeyType)
} }
a.client, err = a.buildACMEClient(account) a.client, err = a.buildACMEClient(account)

View file

@ -11,9 +11,9 @@ import (
"testing" "testing"
"time" "time"
acmeprovider "github.com/containous/traefik/old/provider/acme" acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/tls/generate" "github.com/containous/traefik/tls/generate"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
) )

View file

@ -6,7 +6,7 @@ import (
"os" "os"
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
"github.com/containous/traefik/old/provider/acme" "github.com/containous/traefik/provider/acme"
) )
// LocalStore is a store using a file as storage // LocalStore is a store using a file as storage

View file

@ -8,163 +8,77 @@ import (
"github.com/containous/flaeg/parse" "github.com/containous/flaeg/parse"
"github.com/containous/traefik/acme" "github.com/containous/traefik/acme"
"github.com/containous/traefik/old/api" "github.com/containous/traefik/config/static"
"github.com/containous/traefik/old/configuration" "github.com/containous/traefik/provider"
"github.com/containous/traefik/old/middlewares" acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/old/provider" "github.com/containous/traefik/provider/file"
acmeprovider "github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/provider/boltdb"
"github.com/containous/traefik/old/provider/consul"
"github.com/containous/traefik/old/provider/consulcatalog"
"github.com/containous/traefik/old/provider/docker"
"github.com/containous/traefik/old/provider/dynamodb"
"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/kv"
"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/zk"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/safe"
traefiktls "github.com/containous/traefik/tls" traefiktls "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/elazarl/go-bindata-assetfs" "github.com/elazarl/go-bindata-assetfs"
"github.com/thoas/stats"
) )
func TestDo_globalConfiguration(t *testing.T) { func TestDo_globalConfiguration(t *testing.T) {
config := &configuration.GlobalConfiguration{} config := &static.Configuration{}
config.Debug = true config.Global = &static.Global{
config.CheckNewVersion = true Debug: true,
CheckNewVersion: true,
SendAnonymousUsage: true,
}
config.AccessLog = &types.AccessLog{ config.AccessLog = &types.AccessLog{
FilePath: "AccessLog FilePath", FilePath: "AccessLog FilePath",
Format: "AccessLog Format", Format: "AccessLog Format",
} }
config.LogLevel = "LogLevel" config.Log = &types.TraefikLog{
config.EntryPoints = configuration.EntryPoints{ LogLevel: "LogLevel",
FilePath: "/foo/path",
Format: "json",
}
config.EntryPoints = static.EntryPoints{
"foo": { "foo": {
Address: "foo Address", Address: "foo Address",
Transport: &static.EntryPointsTransport{
RespondingTimeouts: &static.RespondingTimeouts{
ReadTimeout: parse.Duration(111 * time.Second),
WriteTimeout: parse.Duration(111 * time.Second),
IdleTimeout: parse.Duration(111 * time.Second),
},
},
TLS: &traefiktls.TLS{ TLS: &traefiktls.TLS{
MinVersion: "foo MinVersion", MinVersion: "foo MinVersion",
CipherSuites: []string{"foo CipherSuites 1", "foo CipherSuites 2", "foo CipherSuites 3"}, CipherSuites: []string{"foo CipherSuites 1", "foo CipherSuites 2", "foo CipherSuites 3"},
Certificates: traefiktls.Certificates{
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
},
ClientCA: traefiktls.ClientCA{ ClientCA: traefiktls.ClientCA{
Files: traefiktls.FilesOrContents{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"}, Files: traefiktls.FilesOrContents{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"},
Optional: false, Optional: false,
}, },
}, },
Redirect: &types.Redirect{ ProxyProtocol: &static.ProxyProtocol{
Replacement: "foo Replacement",
Regex: "foo Regex",
EntryPoint: "foo EntryPoint",
},
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"},
},
Forward: &types.Forward{
Address: "foo Address",
TLS: &types.ClientTLS{
CA: "foo CA",
Cert: "foo Cert",
Key: "foo Key",
InsecureSkipVerify: true,
},
TrustForwardHeader: true,
},
},
WhiteList: &types.WhiteList{
SourceRange: []string{
"127.0.0.1/32",
},
},
Compress: &configuration.Compress{},
ProxyProtocol: &configuration.ProxyProtocol{
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"}, TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
}, },
}, },
"fii": { "fii": {
Address: "fii Address", Address: "fii Address",
Transport: &static.EntryPointsTransport{
RespondingTimeouts: &static.RespondingTimeouts{
ReadTimeout: parse.Duration(111 * time.Second),
WriteTimeout: parse.Duration(111 * time.Second),
IdleTimeout: parse.Duration(111 * time.Second),
},
},
TLS: &traefiktls.TLS{ TLS: &traefiktls.TLS{
MinVersion: "fii MinVersion", MinVersion: "fii MinVersion",
CipherSuites: []string{"fii CipherSuites 1", "fii CipherSuites 2", "fii CipherSuites 3"}, CipherSuites: []string{"fii CipherSuites 1", "fii CipherSuites 2", "fii CipherSuites 3"},
Certificates: traefiktls.Certificates{
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
},
ClientCA: traefiktls.ClientCA{ ClientCA: traefiktls.ClientCA{
Files: traefiktls.FilesOrContents{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"}, Files: traefiktls.FilesOrContents{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"},
Optional: false, Optional: false,
}, },
}, },
Redirect: &types.Redirect{ ProxyProtocol: &static.ProxyProtocol{
Replacement: "fii Replacement",
Regex: "fii Regex",
EntryPoint: "fii EntryPoint",
},
Auth: &types.Auth{
Basic: &types.Basic{
UsersFile: "fii Basic UsersFile",
Users: types.Users{"fii Basic Users 1", "fii Basic Users 2", "fii Basic Users 3"},
},
Digest: &types.Digest{
UsersFile: "fii Digest UsersFile",
Users: types.Users{"fii Digest Users 1", "fii Digest Users 2", "fii Digest Users 3"},
},
Forward: &types.Forward{
Address: "fii Address",
TLS: &types.ClientTLS{
CA: "fii CA",
Cert: "fii Cert",
Key: "fii Key",
InsecureSkipVerify: true,
},
TrustForwardHeader: true,
},
},
WhiteList: &types.WhiteList{
SourceRange: []string{
"127.0.0.1/32",
},
},
Compress: &configuration.Compress{},
ProxyProtocol: &configuration.ProxyProtocol{
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"}, TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
}, },
}, },
} }
config.Cluster = &types.Cluster{
Node: "Cluster Node",
Store: &types.Store{
Prefix: "Cluster Store Prefix",
// ...
},
}
config.Constraints = types.Constraints{
{
Key: "Constraints Key 1",
Regex: "Constraints Regex 2",
MustMatch: true,
},
{
Key: "Constraints Key 1",
Regex: "Constraints Regex 2",
MustMatch: true,
},
}
config.ACME = &acme.ACME{ config.ACME = &acme.ACME{
Email: "acme Email", Email: "acme Email",
Domains: []types.Domain{ Domains: []types.Domain{
@ -186,33 +100,26 @@ func TestDo_globalConfiguration(t *testing.T) {
// ... // ...
}, },
} }
config.DefaultEntryPoints = configuration.DefaultEntryPoints{"DefaultEntryPoints 1", "DefaultEntryPoints 2", "DefaultEntryPoints 3"} config.Providers = &static.Providers{
config.ProvidersThrottleDuration = parse.Duration(666 * time.Second) ProvidersThrottleDuration: parse.Duration(111 * time.Second),
config.MaxIdleConnsPerHost = 666
config.InsecureSkipVerify = true
config.RootCAs = traefiktls.FilesOrContents{"RootCAs 1", "RootCAs 2", "RootCAs 3"}
config.Retry = &configuration.Retry{
Attempts: 666,
} }
config.HealthCheck = &configuration.HealthCheckConfig{
Interval: parse.Duration(666 * time.Second), config.ServersTransport = &static.ServersTransport{
InsecureSkipVerify: true,
RootCAs: traefiktls.FilesOrContents{"RootCAs 1", "RootCAs 2", "RootCAs 3"},
MaxIdleConnsPerHost: 111,
ForwardingTimeouts: &static.ForwardingTimeouts{
DialTimeout: parse.Duration(111 * time.Second),
ResponseHeaderTimeout: parse.Duration(111 * time.Second),
},
} }
config.API = &api.Handler{
EntryPoint: "traefik", config.API = &static.API{
Dashboard: true, EntryPoint: "traefik",
Debug: true, Dashboard: true,
CurrentConfigurations: &safe.Safe{},
Statistics: &types.Statistics{ Statistics: &types.Statistics{
RecentErrors: 666, RecentErrors: 111,
}, },
Stats: &stats.Stats{
Uptime: time.Now(),
Pid: 666,
ResponseCounts: map[string]int{"foo": 1},
TotalResponseCounts: map[string]int{"bar": 1},
TotalResponseTime: time.Now(),
},
StatsRecorder: &middlewares.StatsRecorder{},
DashboardAssets: &assetfs.AssetFS{ DashboardAssets: &assetfs.AssetFS{
Asset: func(path string) ([]byte, error) { Asset: func(path string) ([]byte, error) {
return nil, nil return nil, nil
@ -225,48 +132,10 @@ func TestDo_globalConfiguration(t *testing.T) {
}, },
Prefix: "fii", Prefix: "fii",
}, },
Middlewares: []string{"first", "second"},
} }
config.RespondingTimeouts = &configuration.RespondingTimeouts{
ReadTimeout: parse.Duration(666 * time.Second), config.Providers.File = &file.Provider{
WriteTimeout: parse.Duration(666 * time.Second),
IdleTimeout: parse.Duration(666 * time.Second),
}
config.ForwardingTimeouts = &configuration.ForwardingTimeouts{
DialTimeout: parse.Duration(666 * time.Second),
ResponseHeaderTimeout: parse.Duration(666 * time.Second),
}
config.Docker = &docker.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "docker Filename",
Constraints: types.Constraints{
{
Key: "docker Constraints Key 1",
Regex: "docker Constraints Regex 2",
MustMatch: true,
},
{
Key: "docker Constraints Key 1",
Regex: "docker Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "docker Endpoint",
Domain: "docker Domain",
TLS: &types.ClientTLS{
CA: "docker CA",
Cert: "docker Cert",
Key: "docker Key",
InsecureSkipVerify: true,
},
ExposedByDefault: true,
UseBindPortIP: true,
SwarmMode: true,
}
config.File = &file.Provider{
BaseProvider: provider.BaseProvider{ BaseProvider: provider.BaseProvider{
Watch: true, Watch: true,
Filename: "file Filename", Filename: "file Filename",
@ -287,368 +156,8 @@ func TestDo_globalConfiguration(t *testing.T) {
}, },
Directory: "file Directory", Directory: "file Directory",
} }
config.Marathon = &marathon.Provider{
BaseProvider: provider.BaseProvider{ // FIXME Test the other providers once they are migrated
Watch: true,
Filename: "marathon Filename",
Constraints: types.Constraints{
{
Key: "marathon Constraints Key 1",
Regex: "marathon Constraints Regex 2",
MustMatch: true,
},
{
Key: "marathon Constraints Key 1",
Regex: "marathon Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "",
Domain: "",
ExposedByDefault: true,
GroupsAsSubDomains: true,
DCOSToken: "",
MarathonLBCompatibility: true,
TLS: &types.ClientTLS{
CA: "marathon CA",
Cert: "marathon Cert",
Key: "marathon Key",
InsecureSkipVerify: true,
},
DialerTimeout: parse.Duration(666 * time.Second),
KeepAlive: parse.Duration(666 * time.Second),
ForceTaskHostname: true,
Basic: &marathon.Basic{
HTTPBasicAuthUser: "marathon HTTPBasicAuthUser",
HTTPBasicPassword: "marathon HTTPBasicPassword",
},
RespectReadinessChecks: true,
}
config.ConsulCatalog = &consulcatalog.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "ConsulCatalog Filename",
Constraints: types.Constraints{
{
Key: "ConsulCatalog Constraints Key 1",
Regex: "ConsulCatalog Constraints Regex 2",
MustMatch: true,
},
{
Key: "ConsulCatalog Constraints Key 1",
Regex: "ConsulCatalog Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "ConsulCatalog Endpoint",
Domain: "ConsulCatalog Domain",
ExposedByDefault: true,
Prefix: "ConsulCatalog Prefix",
FrontEndRule: "ConsulCatalog FrontEndRule",
}
config.Kubernetes = &kubernetes.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "k8s Filename",
Constraints: types.Constraints{
{
Key: "k8s Constraints Key 1",
Regex: "k8s Constraints Regex 2",
MustMatch: true,
},
{
Key: "k8s Constraints Key 1",
Regex: "k8s Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "k8s Endpoint",
Token: "k8s Token",
CertAuthFilePath: "k8s CertAuthFilePath",
DisablePassHostHeaders: true,
Namespaces: kubernetes.Namespaces{"k8s Namespaces 1", "k8s Namespaces 2", "k8s Namespaces 3"},
LabelSelector: "k8s LabelSelector",
}
config.Mesos = &mesos.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "mesos Filename",
Constraints: types.Constraints{
{
Key: "mesos Constraints Key 1",
Regex: "mesos Constraints Regex 2",
MustMatch: true,
},
{
Key: "mesos Constraints Key 1",
Regex: "mesos Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "mesos Endpoint",
Domain: "mesos Domain",
ExposedByDefault: true,
GroupsAsSubDomains: true,
ZkDetectionTimeout: 666,
RefreshSeconds: 666,
IPSources: "mesos IPSources",
StateTimeoutSecond: 666,
Masters: []string{"mesos Masters 1", "mesos Masters 2", "mesos Masters 3"},
}
config.Eureka = &eureka.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "eureka Filename",
Constraints: types.Constraints{
{
Key: "eureka Constraints Key 1",
Regex: "eureka Constraints Regex 2",
MustMatch: true,
},
{
Key: "eureka Constraints Key 1",
Regex: "eureka Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "eureka Endpoint",
RefreshSeconds: parse.Duration(30 * time.Second),
}
config.ECS = &ecs.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "ecs Filename",
Constraints: types.Constraints{
{
Key: "ecs Constraints Key 1",
Regex: "ecs Constraints Regex 2",
MustMatch: true,
},
{
Key: "ecs Constraints Key 1",
Regex: "ecs Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Domain: "ecs Domain",
ExposedByDefault: true,
RefreshSeconds: 666,
Clusters: ecs.Clusters{"ecs Clusters 1", "ecs Clusters 2", "ecs Clusters 3"},
AutoDiscoverClusters: true,
Region: "ecs Region",
AccessKeyID: "ecs AccessKeyID",
SecretAccessKey: "ecs SecretAccessKey",
}
config.Rancher = &rancher.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "rancher Filename",
Constraints: types.Constraints{
{
Key: "rancher Constraints Key 1",
Regex: "rancher Constraints Regex 2",
MustMatch: true,
},
{
Key: "rancher Constraints Key 1",
Regex: "rancher Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
APIConfiguration: rancher.APIConfiguration{
Endpoint: "rancher Endpoint",
AccessKey: "rancher AccessKey",
SecretKey: "rancher SecretKey",
},
API: &rancher.APIConfiguration{
Endpoint: "rancher Endpoint",
AccessKey: "rancher AccessKey",
SecretKey: "rancher SecretKey",
},
Metadata: &rancher.MetadataConfiguration{
IntervalPoll: true,
Prefix: "rancher Metadata Prefix",
},
Domain: "rancher Domain",
RefreshSeconds: 666,
ExposedByDefault: true,
EnableServiceHealthFilter: true,
}
config.DynamoDB = &dynamodb.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "dynamodb Filename",
Constraints: types.Constraints{
{
Key: "dynamodb Constraints Key 1",
Regex: "dynamodb Constraints Regex 2",
MustMatch: true,
},
{
Key: "dynamodb Constraints Key 1",
Regex: "dynamodb Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
AccessKeyID: "dynamodb AccessKeyID",
RefreshSeconds: 666,
Region: "dynamodb Region",
SecretAccessKey: "dynamodb SecretAccessKey",
TableName: "dynamodb TableName",
Endpoint: "dynamodb Endpoint",
}
config.Etcd = &etcd.Provider{
Provider: kv.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "etcd Filename",
Constraints: types.Constraints{
{
Key: "etcd Constraints Key 1",
Regex: "etcd Constraints Regex 2",
MustMatch: true,
},
{
Key: "etcd Constraints Key 1",
Regex: "etcd Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "etcd Endpoint",
Prefix: "etcd Prefix",
TLS: &types.ClientTLS{
CA: "etcd CA",
Cert: "etcd Cert",
Key: "etcd Key",
InsecureSkipVerify: true,
},
Username: "etcd Username",
Password: "etcd Password",
},
}
config.Zookeeper = &zk.Provider{
Provider: kv.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "zk Filename",
Constraints: types.Constraints{
{
Key: "zk Constraints Key 1",
Regex: "zk Constraints Regex 2",
MustMatch: true,
},
{
Key: "zk Constraints Key 1",
Regex: "zk Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "zk Endpoint",
Prefix: "zk Prefix",
TLS: &types.ClientTLS{
CA: "zk CA",
Cert: "zk Cert",
Key: "zk Key",
InsecureSkipVerify: true,
},
Username: "zk Username",
Password: "zk Password",
},
}
config.Boltdb = &boltdb.Provider{
Provider: kv.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "boltdb Filename",
Constraints: types.Constraints{
{
Key: "boltdb Constraints Key 1",
Regex: "boltdb Constraints Regex 2",
MustMatch: true,
},
{
Key: "boltdb Constraints Key 1",
Regex: "boltdb Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "boltdb Endpoint",
Prefix: "boltdb Prefix",
TLS: &types.ClientTLS{
CA: "boltdb CA",
Cert: "boltdb Cert",
Key: "boltdb Key",
InsecureSkipVerify: true,
},
Username: "boltdb Username",
Password: "boltdb Password",
},
}
config.Consul = &consul.Provider{
Provider: kv.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "consul Filename",
Constraints: types.Constraints{
{
Key: "consul Constraints Key 1",
Regex: "consul Constraints Regex 2",
MustMatch: true,
},
{
Key: "consul Constraints Key 1",
Regex: "consul Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "consul Endpoint",
Prefix: "consul Prefix",
TLS: &types.ClientTLS{
CA: "consul CA",
Cert: "consul Cert",
Key: "consul Key",
InsecureSkipVerify: true,
},
Username: "consul Username",
Password: "consul Password",
},
}
cleanJSON, err := Do(config, true) cleanJSON, err := Do(config, true)
if err != nil { if err != nil {

View file

@ -5,36 +5,19 @@ import (
"github.com/containous/traefik/anonymize" "github.com/containous/traefik/anonymize"
"github.com/containous/traefik/cmd" "github.com/containous/traefik/cmd"
"github.com/containous/traefik/old/configuration" "github.com/containous/traefik/config/static"
"github.com/containous/traefik/old/provider/file"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/tls"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func Test_createReport(t *testing.T) { func Test_createReport(t *testing.T) {
traefikConfiguration := &cmd.TraefikConfiguration{ traefikConfiguration := &cmd.TraefikConfiguration{
ConfigFile: "FOO", ConfigFile: "FOO",
GlobalConfiguration: configuration.GlobalConfiguration{ Configuration: static.Configuration{
EntryPoints: configuration.EntryPoints{ EntryPoints: static.EntryPoints{
"goo": &configuration.EntryPoint{ "goo": &static.EntryPoint{
Address: "hoo.bar", 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) assert.NoError(t, err, report)
// exported anonymous configuration // exported anonymous configuration
assert.NotContains(t, "web Basic Users ", report)
assert.NotContains(t, "foo Digest Users ", report)
assert.NotContains(t, "hoo.bar", report) assert.NotContains(t, "hoo.bar", report)
} }
func Test_anonymize_traefikConfiguration(t *testing.T) { func Test_anonymize_traefikConfiguration(t *testing.T) {
traefikConfiguration := &cmd.TraefikConfiguration{ traefikConfiguration := &cmd.TraefikConfiguration{
ConfigFile: "FOO", ConfigFile: "FOO",
GlobalConfiguration: configuration.GlobalConfiguration{ Configuration: static.Configuration{
EntryPoints: configuration.EntryPoints{ EntryPoints: static.EntryPoints{
"goo": &configuration.EntryPoint{ "goo": &static.EntryPoint{
Address: "hoo.bar", Address: "hoo.bar",
}, },
}, },
File: &file.Provider{
Directory: "BAR",
},
}, },
} }
_, err := anonymize.Do(traefikConfiguration, true) _, err := anonymize.Do(traefikConfiguration, true)
assert.NoError(t, err) 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" "time"
"github.com/containous/flaeg/parse" "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/configuration"
"github.com/containous/traefik/old/middlewares/accesslog" "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/boltdb"
"github.com/containous/traefik/old/provider/consul" "github.com/containous/traefik/old/provider/consul"
"github.com/containous/traefik/old/provider/consulcatalog" "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/ecs"
"github.com/containous/traefik/old/provider/etcd" "github.com/containous/traefik/old/provider/etcd"
"github.com/containous/traefik/old/provider/eureka" "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/kubernetes"
"github.com/containous/traefik/old/provider/marathon" "github.com/containous/traefik/old/provider/marathon"
"github.com/containous/traefik/old/provider/mesos" "github.com/containous/traefik/old/provider/mesos"
"github.com/containous/traefik/old/provider/rancher" "github.com/containous/traefik/old/provider/rancher"
"github.com/containous/traefik/old/provider/rest" "github.com/containous/traefik/old/provider/rest"
"github.com/containous/traefik/old/provider/zk" "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 // TraefikConfiguration holds GlobalConfiguration and other stuff
type TraefikConfiguration struct { type TraefikConfiguration struct {
configuration.GlobalConfiguration `mapstructure:",squash" export:"true"` static.Configuration `mapstructure:",squash" export:"true"`
ConfigFile string `short:"c" description:"Configuration file to use (TOML)." 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 // NewTraefikDefaultPointersConfiguration creates a TraefikConfiguration with pointers default values
func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration { 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 // default File
var defaultFile file.Provider var defaultFile file.Provider
defaultFile.Watch = true defaultFile.Watch = true
defaultFile.Filename = "" // needs equivalent to viper.ConfigFileUsed() 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 // default Ping
var defaultPing = ping.Handler{ var defaultPing = ping.Handler{
EntryPoint: "traefik", 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 // default Tracing
defaultTracing := tracing.Tracing{ defaultTracing := static.Tracing{
Backend: "jaeger", Backend: "jaeger",
ServiceName: "traefik", ServiceName: "traefik",
SpanNameLimit: 0, SpanNameLimit: 0,
@ -210,13 +113,8 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
}, },
} }
// default LifeCycle
defaultLifeCycle := configuration.LifeCycle{
GraceTimeOut: parse.Duration(configuration.DefaultGraceTimeout),
}
// default ApiConfiguration // default ApiConfiguration
defaultAPI := api.Handler{ defaultAPI := static.API{
EntryPoint: "traefik", EntryPoint: "traefik",
Dashboard: true, Dashboard: true,
} }
@ -245,65 +143,129 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
}, },
} }
defaultResolver := configuration.HostResolverConfig{ defaultResolver := static.HostResolverConfig{
CnameFlattening: false, CnameFlattening: false,
ResolvConfig: "/etc/resolv.conf", ResolvConfig: "/etc/resolv.conf",
ResolvDepth: 5, ResolvDepth: 5,
} }
defaultConfiguration := configuration.GlobalConfiguration{ var defaultDocker docker.Provider
Docker: &defaultDocker, defaultDocker.Watch = true
File: &defaultFile, defaultDocker.ExposedByDefault = true
Rest: &defaultRest, defaultDocker.Endpoint = "unix:///var/run/docker.sock"
Marathon: &defaultMarathon, defaultDocker.SwarmMode = false
Consul: &defaultConsul,
ConsulCatalog: &defaultConsulCatalog, // default Rest
Etcd: &defaultEtcd, var defaultRest rest.Provider
Zookeeper: &defaultZookeeper, defaultRest.EntryPoint = configuration.DefaultInternalEntryPointName
Boltdb: &defaultBoltDb,
Kubernetes: &defaultKubernetes, // default Marathon
Mesos: &defaultMesos, var defaultMarathon marathon.Provider
ECS: &defaultECS, defaultMarathon.Watch = true
Rancher: &defaultRancher, defaultMarathon.Endpoint = "http://127.0.0.1:8080"
Eureka: &defaultEureka, defaultMarathon.ExposedByDefault = true
DynamoDB: &defaultDynamoDB, defaultMarathon.DialerTimeout = parse.Duration(5 * time.Second)
Retry: &configuration.Retry{}, defaultMarathon.ResponseHeaderTimeout = parse.Duration(60 * time.Second)
HealthCheck: &healthCheck, defaultMarathon.TLSHandshakeTimeout = parse.Duration(5 * time.Second)
RespondingTimeouts: &respondingTimeouts, defaultMarathon.KeepAlive = parse.Duration(10 * time.Second)
ForwardingTimeouts: &forwardingTimeouts,
TraefikLog: &defaultTraefikLog, // default Consul
AccessLog: &defaultAccessLog, var defaultConsul consul.Provider
LifeCycle: &defaultLifeCycle, defaultConsul.Watch = true
Ping: &defaultPing, defaultConsul.Endpoint = "127.0.0.1:8500"
API: &defaultAPI, defaultConsul.Prefix = "traefik"
Metrics: &defaultMetrics,
Tracing: &defaultTracing, // default CatalogProvider
HostResolver: &defaultResolver, 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{ return &TraefikConfiguration{
GlobalConfiguration: defaultConfiguration, Configuration: static.Configuration{
} Providers: &defaultProviders,
} Log: &defaultTraefikLog,
AccessLog: &defaultAccessLog,
// NewTraefikConfiguration creates a TraefikConfiguration with default values Ping: &defaultPing,
func NewTraefikConfiguration() *TraefikConfiguration { API: &defaultAPI,
return &TraefikConfiguration{ Metrics: &defaultMetrics,
GlobalConfiguration: configuration.GlobalConfiguration{ Tracing: &defaultTracing,
EntryPoints: map[string]*configuration.EntryPoint{}, HostResolver: &defaultResolver,
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,
}, },
ConfigFile: "",
} }
} }

View file

@ -10,7 +10,7 @@ import (
"github.com/containous/flaeg" "github.com/containous/flaeg"
"github.com/containous/traefik/cmd" "github.com/containous/traefik/cmd"
"github.com/containous/traefik/old/configuration" "github.com/containous/traefik/config/static"
) )
// NewCmd builds a new HealthCheck command // NewCmd builds a new HealthCheck command
@ -29,9 +29,9 @@ func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfi
func runCmd(traefikConfiguration *cmd.TraefikConfiguration) func() error { func runCmd(traefikConfiguration *cmd.TraefikConfiguration) func() error {
return 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 { if errPing != nil {
fmt.Printf("Error calling healthcheck: %s\n", errPing) fmt.Printf("Error calling healthcheck: %s\n", errPing)
os.Exit(1) os.Exit(1)
@ -47,17 +47,18 @@ func runCmd(traefikConfiguration *cmd.TraefikConfiguration) func() error {
} }
// Do try to do a healthcheck // Do try to do a healthcheck
func Do(globalConfiguration configuration.GlobalConfiguration) (*http.Response, error) { func Do(staticConfiguration static.Configuration) (*http.Response, error) {
if globalConfiguration.Ping == nil { if staticConfiguration.Ping == nil {
return nil, errors.New("please enable `ping` to use health check") 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 { if !ok {
return nil, errors.New("missing `ping` entrypoint") return nil, errors.New("missing `ping` entrypoint")
} }
client := &http.Client{Timeout: 5 * time.Second} client := &http.Client{Timeout: 5 * time.Second}
protocol := "http" protocol := "http"
if pingEntryPoint.TLS != nil { if pingEntryPoint.TLS != nil {
protocol = "https" protocol = "https"
tr := &http.Transport{ tr := &http.Transport{
@ -65,6 +66,7 @@ func Do(globalConfiguration configuration.GlobalConfiguration) (*http.Response,
} }
client.Transport = tr client.Transport = tr
} }
path := "/" path := "/"
return client.Head(protocol + "://" + pingEntryPoint.Address + path + "ping") 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") return fmt.Errorf("error using command storeconfig, no Key-value store defined")
} }
fileConfig := traefikConfiguration.GlobalConfiguration.File fileConfig := traefikConfiguration.Providers.File
if fileConfig != nil { if fileConfig != nil {
traefikConfiguration.GlobalConfiguration.File = nil traefikConfiguration.Providers.File = nil
if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 { if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 {
fileConfig.Filename = traefikConfiguration.ConfigFile fileConfig.Filename = traefikConfiguration.ConfigFile
} }
} }
jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration) jsonConf, err := json.Marshal(traefikConfiguration.Configuration)
if err != nil { if err != nil {
return err return err
} }
stdlog.Printf("Storing configuration: %s\n", jsonConf) stdlog.Printf("Storing configuration: %s\n", jsonConf)
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration) err = kv.StoreConfig(traefikConfiguration.Configuration)
if err != nil { if err != nil {
return err 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{} account := &acme.Account{}
// Migrate ACME data from file to KV store if needed // Migrate ACME data from file to KV store if needed
if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 { if len(traefikConfiguration.Configuration.ACME.StorageFile) > 0 {
account, err = migrateACMEData(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) account, err = migrateACMEData(traefikConfiguration.Configuration.ACME.StorageFile)
if err != nil { if err != nil {
return err return err
} }
} }
accountInitialized, err := keyExists(kv, traefikConfiguration.GlobalConfiguration.ACME.Storage) accountInitialized, err := keyExists(kv, traefikConfiguration.Configuration.ACME.Storage)
if err != nil && err != store.ErrKeyNotFound { if err != nil && err != store.ErrKeyNotFound {
return err return err
} }
// Check to see if ACME account object is already in kv store // 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 // Store the ACME Account into the KV Store
// Certificates in KV Store will be overridden // Certificates in KV Store will be overridden
@ -103,7 +103,7 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
source := staert.KvSource{ source := staert.KvSource{
Store: kv, Store: kv,
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage, Prefix: traefikConfiguration.Configuration.ACME.Storage,
} }
err = source.StoreConfig(meta) err = source.StoreConfig(meta)
@ -182,29 +182,29 @@ func CreateKvSource(traefikConfiguration *cmd.TraefikConfiguration) (*staert.KvS
var err error var err error
switch { switch {
case traefikConfiguration.Consul != nil: case traefikConfiguration.Providers.Consul != nil:
kvStore, err = traefikConfiguration.Consul.CreateStore() kvStore, err = traefikConfiguration.Providers.Consul.CreateStore()
kv = &staert.KvSource{ kv = &staert.KvSource{
Store: kvStore, Store: kvStore,
Prefix: traefikConfiguration.Consul.Prefix, Prefix: traefikConfiguration.Providers.Consul.Prefix,
} }
case traefikConfiguration.Etcd != nil: case traefikConfiguration.Providers.Etcd != nil:
kvStore, err = traefikConfiguration.Etcd.CreateStore() kvStore, err = traefikConfiguration.Providers.Etcd.CreateStore()
kv = &staert.KvSource{ kv = &staert.KvSource{
Store: kvStore, Store: kvStore,
Prefix: traefikConfiguration.Etcd.Prefix, Prefix: traefikConfiguration.Providers.Etcd.Prefix,
} }
case traefikConfiguration.Zookeeper != nil: case traefikConfiguration.Providers.Zookeeper != nil:
kvStore, err = traefikConfiguration.Zookeeper.CreateStore() kvStore, err = traefikConfiguration.Providers.Zookeeper.CreateStore()
kv = &staert.KvSource{ kv = &staert.KvSource{
Store: kvStore, Store: kvStore,
Prefix: traefikConfiguration.Zookeeper.Prefix, Prefix: traefikConfiguration.Providers.Zookeeper.Prefix,
} }
case traefikConfiguration.Boltdb != nil: case traefikConfiguration.Providers.Boltdb != nil:
kvStore, err = traefikConfiguration.Boltdb.CreateStore() kvStore, err = traefikConfiguration.Providers.Boltdb.CreateStore()
kv = &staert.KvSource{ kv = &staert.KvSource{
Store: kvStore, Store: kvStore,
Prefix: traefikConfiguration.Boltdb.Prefix, Prefix: traefikConfiguration.Providers.Boltdb.Prefix,
} }
} }
return kv, err return kv, err

View file

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

View file

@ -10,6 +10,7 @@ import (
"time" "time"
"github.com/containous/traefik/anonymize" "github.com/containous/traefik/anonymize"
"github.com/containous/traefik/config/static"
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
"github.com/containous/traefik/old/configuration" "github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/version" "github.com/containous/traefik/version"
@ -29,15 +30,15 @@ type data struct {
} }
// Collect anonymous data. // Collect anonymous data.
func Collect(globalConfiguration *configuration.GlobalConfiguration) error { func Collect(staticConfiguration *static.Configuration) error {
anonConfig, err := anonymize.Do(globalConfiguration, false) anonConfig, err := anonymize.Do(staticConfiguration, false)
if err != nil { if err != nil {
return err return err
} }
log.Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig) log.Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig)
hashConf, err := hashstructure.Hash(globalConfiguration, nil) hashConf, err := hashstructure.Hash(staticConfiguration, nil)
if err != nil { if err != nil {
return err return err
} }

View file

@ -0,0 +1,169 @@
package static
import (
"fmt"
"strings"
"github.com/containous/traefik/log"
"github.com/containous/traefik/tls"
)
// EntryPoint holds the entry point configuration.
type EntryPoint struct {
Address string
Transport *EntryPointsTransport
TLS *tls.TLS
ProxyProtocol *ProxyProtocol
}
// ProxyProtocol contains Proxy-Protocol configuration.
type ProxyProtocol struct {
Insecure bool `export:"true"`
TrustedIPs []string
}
// EntryPoints holds the HTTP entry point list.
type EntryPoints map[string]*EntryPoint
// EntryPointsTransport configures communication between clients and Traefik.
type EntryPointsTransport struct {
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"`
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
}
// 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 (ep EntryPoints) String() string {
return fmt.Sprintf("%+v", map[string]*EntryPoint(ep))
}
// Get return the EntryPoints map.
func (ep *EntryPoints) Get() interface{} {
return *ep
}
// SetValue sets the EntryPoints map with val.
func (ep *EntryPoints) SetValue(val interface{}) {
*ep = val.(EntryPoints)
}
// Type is type of the struct.
func (ep *EntryPoints) Type() string {
return "entrypoints"
}
// 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 (ep *EntryPoints) Set(value string) error {
result := parseEntryPointsConfiguration(value)
configTLS, err := makeEntryPointTLS(result)
if err != nil {
return err
}
(*ep)[result["name"]] = &EntryPoint{
Address: result["address"],
TLS: configTLS,
ProxyProtocol: makeEntryPointProxyProtocol(result),
}
return nil
}
func makeEntryPointProxyProtocol(result map[string]string) *ProxyProtocol {
var proxyProtocol *ProxyProtocol
ppTrustedIPs := result["proxyprotocol_trustedips"]
if len(result["proxyprotocol_insecure"]) > 0 || len(ppTrustedIPs) > 0 {
proxyProtocol = &ProxyProtocol{
Insecure: toBool(result, "proxyprotocol_insecure"),
}
if len(ppTrustedIPs) > 0 {
proxyProtocol.TrustedIPs = strings.Split(ppTrustedIPs, ",")
}
}
if proxyProtocol != nil && proxyProtocol.Insecure {
log.Warn("ProxyProtocol.insecure:true is dangerous. Please use 'ProxyProtocol.TrustedIPs:IPs' and remove 'ProxyProtocol.insecure:true'")
}
return proxyProtocol
}
func makeEntryPointTLS(result map[string]string) (*tls.TLS, error) {
var configTLS *tls.TLS
if len(result["tls"]) > 0 {
certs := tls.Certificates{}
if err := certs.Set(result["tls"]); err != nil {
return nil, err
}
configTLS = &tls.TLS{}
} else if len(result["tls_acme"]) > 0 {
configTLS = &tls.TLS{}
}
if configTLS != nil {
if len(result["ca"]) > 0 {
files := tls.FilesOrContents{}
files.Set(result["ca"])
optional := toBool(result, "ca_optional")
configTLS.ClientCA = tls.ClientCA{
Files: files,
Optional: optional,
}
}
if len(result["tls_minversion"]) > 0 {
configTLS.MinVersion = result["tls_minversion"]
}
if len(result["tls_ciphersuites"]) > 0 {
configTLS.CipherSuites = strings.Split(result["tls_ciphersuites"], ",")
}
if len(result["tls_snistrict"]) > 0 {
configTLS.SniStrict = toBool(result, "tls_snistrict")
}
if len(result["tls_defaultcertificate_cert"]) > 0 && len(result["tls_defaultcertificate_key"]) > 0 {
configTLS.DefaultCertificate = &tls.Certificate{
CertFile: tls.FileOrContent(result["tls_defaultcertificate_cert"]),
KeyFile: tls.FileOrContent(result["tls_defaultcertificate_key"]),
}
}
}
return configTLS, nil
}
func parseEntryPointsConfiguration(raw string) map[string]string {
sections := strings.Fields(raw)
config := make(map[string]string)
for _, part := range sections {
field := strings.SplitN(part, ":", 2)
name := strings.ToLower(strings.Replace(field[0], ".", "_", -1))
if len(field) > 1 {
config[name] = field[1]
} else {
if strings.EqualFold(name, "TLS") {
config["tls_acme"] = "TLS"
} else {
config[name] = ""
}
}
}
return config
}
func toBool(conf map[string]string, key string) bool {
if val, ok := conf[key]; ok {
return strings.EqualFold(val, "true") ||
strings.EqualFold(val, "enable") ||
strings.EqualFold(val, "on")
}
return false
}

View file

@ -1,9 +1,8 @@
package configuration package static
import ( import (
"testing" "testing"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/tls" "github.com/containous/traefik/tls"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -186,277 +185,70 @@ func TestEntryPoints_Set(t *testing.T) {
name: "all parameters camelcase", name: "all parameters camelcase",
expression: "Name:foo " + expression: "Name:foo " +
"Address::8000 " + "Address::8000 " +
"TLS:goo,gii;foo,fii " +
"TLS " + "TLS " +
"TLS.MinVersion:VersionTLS11 " + "TLS.MinVersion:VersionTLS11 " +
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " + "TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
"CA:car " + "CA:car " +
"CA.Optional:true " + "CA.Optional:true " +
"Redirect.EntryPoint:https " + "ProxyProtocol.TrustedIPs:192.168.0.1 ",
"Redirect.Regex:http://localhost/(.*) " +
"Redirect.Replacement:http://mydomain/$1 " +
"Redirect.Permanent:true " +
"Compress:true " +
"ProxyProtocol.TrustedIPs:192.168.0.1 " +
"ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24 " +
"Auth.Basic.Realm:myRealm " +
"Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 " +
"Auth.Basic.RemoveHeader:true " +
"Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
"Auth.Digest.RemoveHeader:true " +
"Auth.HeaderField:X-WebAuth-User " +
"Auth.Forward.Address:https://authserver.com/auth " +
"Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret " +
"Auth.Forward.TrustForwardHeader:true " +
"Auth.Forward.TLS.CA:path/to/local.crt " +
"Auth.Forward.TLS.CAOptional:true " +
"Auth.Forward.TLS.Cert:path/to/foo.cert " +
"Auth.Forward.TLS.Key:path/to/foo.key " +
"Auth.Forward.TLS.InsecureSkipVerify:true " +
"WhiteList.SourceRange:10.42.0.0/16,152.89.1.33/32,afed:be44::/16 " +
"WhiteList.IPStrategy.depth:3 " +
"WhiteList.IPStrategy.ExcludedIPs:10.0.0.3/24,20.0.0.3/24 " +
"ClientIPStrategy.depth:3 " +
"ClientIPStrategy.ExcludedIPs:10.0.0.3/24,20.0.0.3/24 ",
expectedEntryPointName: "foo", expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{ expectedEntryPoint: &EntryPoint{
Address: ":8000", Address: ":8000",
TLS: &tls.TLS{ TLS: &tls.TLS{
MinVersion: "VersionTLS11", MinVersion: "VersionTLS11",
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"}, CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
Certificates: tls.Certificates{
{
CertFile: tls.FileOrContent("goo"),
KeyFile: tls.FileOrContent("gii"),
},
{
CertFile: tls.FileOrContent("foo"),
KeyFile: tls.FileOrContent("fii"),
},
},
ClientCA: tls.ClientCA{ ClientCA: tls.ClientCA{
Files: tls.FilesOrContents{"car"}, Files: tls.FilesOrContents{"car"},
Optional: true, Optional: true,
}, },
}, },
Redirect: &types.Redirect{
EntryPoint: "https",
Regex: "http://localhost/(.*)",
Replacement: "http://mydomain/$1",
Permanent: true,
},
Auth: &types.Auth{
Basic: &types.Basic{
Realm: "myRealm",
RemoveHeader: true,
Users: types.Users{
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
},
},
Digest: &types.Digest{
RemoveHeader: true,
Users: types.Users{
"test:traefik:a2688e031edb4be6a3797f3882655c05",
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
},
},
Forward: &types.Forward{
Address: "https://authserver.com/auth",
AuthResponseHeaders: []string{"X-Auth", "X-Test", "X-Secret"},
TLS: &types.ClientTLS{
CA: "path/to/local.crt",
CAOptional: true,
Cert: "path/to/foo.cert",
Key: "path/to/foo.key",
InsecureSkipVerify: true,
},
TrustForwardHeader: true,
},
HeaderField: "X-WebAuth-User",
},
WhiteList: &types.WhiteList{
SourceRange: []string{
"10.42.0.0/16",
"152.89.1.33/32",
"afed:be44::/16",
},
IPStrategy: &types.IPStrategy{
Depth: 3,
ExcludedIPs: []string{
"10.0.0.3/24",
"20.0.0.3/24",
},
},
},
Compress: &Compress{},
ProxyProtocol: &ProxyProtocol{ ProxyProtocol: &ProxyProtocol{
Insecure: false, Insecure: false,
TrustedIPs: []string{"192.168.0.1"}, TrustedIPs: []string{"192.168.0.1"},
}, },
ForwardedHeaders: &ForwardedHeaders{ // FIXME Test ServersTransport
Insecure: false,
TrustedIPs: []string{
"10.0.0.3/24",
"20.0.0.3/24",
},
},
ClientIPStrategy: &types.IPStrategy{
Depth: 3,
ExcludedIPs: []string{
"10.0.0.3/24",
"20.0.0.3/24",
},
},
}, },
}, },
{ {
name: "all parameters lowercase", name: "all parameters lowercase",
expression: "Name:foo " + expression: "Name:foo " +
"address::8000 " + "address::8000 " +
"tls:goo,gii;foo,fii " +
"tls " + "tls " +
"tls.minversion:VersionTLS11 " + "tls.minversion:VersionTLS11 " +
"tls.ciphersuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " + "tls.ciphersuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
"ca:car " + "ca:car " +
"ca.Optional:true " + "ca.Optional:true " +
"redirect.entryPoint:https " + "proxyProtocol.TrustedIPs:192.168.0.1 ",
"redirect.regex:http://localhost/(.*) " +
"redirect.replacement:http://mydomain/$1 " +
"redirect.permanent:true " +
"compress:true " +
"whiteList.sourceRange:10.42.0.0/16,152.89.1.33/32,afed:be44::/16 " +
"proxyProtocol.TrustedIPs:192.168.0.1 " +
"forwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24 " +
"auth.basic.realm:myRealm " +
"auth.basic.users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 " +
"auth.digest.users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
"auth.headerField:X-WebAuth-User " +
"auth.forward.address:https://authserver.com/auth " +
"auth.forward.authResponseHeaders:X-Auth,X-Test,X-Secret " +
"auth.forward.trustForwardHeader:true " +
"auth.forward.tls.ca:path/to/local.crt " +
"auth.forward.tls.caOptional:true " +
"auth.forward.tls.cert:path/to/foo.cert " +
"auth.forward.tls.key:path/to/foo.key " +
"auth.forward.tls.insecureSkipVerify:true ",
expectedEntryPointName: "foo", expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{ expectedEntryPoint: &EntryPoint{
Address: ":8000", Address: ":8000",
TLS: &tls.TLS{ TLS: &tls.TLS{
MinVersion: "VersionTLS11", MinVersion: "VersionTLS11",
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"}, CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
Certificates: tls.Certificates{
{
CertFile: tls.FileOrContent("goo"),
KeyFile: tls.FileOrContent("gii"),
},
{
CertFile: tls.FileOrContent("foo"),
KeyFile: tls.FileOrContent("fii"),
},
},
ClientCA: tls.ClientCA{ ClientCA: tls.ClientCA{
Files: tls.FilesOrContents{"car"}, Files: tls.FilesOrContents{"car"},
Optional: true, Optional: true,
}, },
}, },
Redirect: &types.Redirect{
EntryPoint: "https",
Regex: "http://localhost/(.*)",
Replacement: "http://mydomain/$1",
Permanent: true,
},
Auth: &types.Auth{
Basic: &types.Basic{
Realm: "myRealm",
Users: types.Users{
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
},
},
Digest: &types.Digest{
Users: types.Users{
"test:traefik:a2688e031edb4be6a3797f3882655c05",
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
},
},
Forward: &types.Forward{
Address: "https://authserver.com/auth",
AuthResponseHeaders: []string{"X-Auth", "X-Test", "X-Secret"},
TLS: &types.ClientTLS{
CA: "path/to/local.crt",
CAOptional: true,
Cert: "path/to/foo.cert",
Key: "path/to/foo.key",
InsecureSkipVerify: true,
},
TrustForwardHeader: true,
},
HeaderField: "X-WebAuth-User",
},
WhiteList: &types.WhiteList{
SourceRange: []string{
"10.42.0.0/16",
"152.89.1.33/32",
"afed:be44::/16",
},
},
Compress: &Compress{},
ProxyProtocol: &ProxyProtocol{ ProxyProtocol: &ProxyProtocol{
Insecure: false, Insecure: false,
TrustedIPs: []string{"192.168.0.1"}, TrustedIPs: []string{"192.168.0.1"},
}, },
ForwardedHeaders: &ForwardedHeaders{ // FIXME Test ServersTransport
Insecure: false,
TrustedIPs: []string{
"10.0.0.3/24",
"20.0.0.3/24",
},
},
}, },
}, },
{ {
name: "default", name: "default",
expression: "Name:foo", expression: "Name:foo",
expectedEntryPointName: "foo", expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{ expectedEntryPoint: &EntryPoint{},
ForwardedHeaders: &ForwardedHeaders{Insecure: false},
},
},
{
name: "ForwardedHeaders insecure true",
expression: "Name:foo ForwardedHeaders.insecure:true",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
ForwardedHeaders: &ForwardedHeaders{Insecure: true},
},
},
{
name: "ForwardedHeaders insecure false",
expression: "Name:foo ForwardedHeaders.insecure:false",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
ForwardedHeaders: &ForwardedHeaders{Insecure: false},
},
},
{
name: "ForwardedHeaders TrustedIPs",
expression: "Name:foo ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
ForwardedHeaders: &ForwardedHeaders{
TrustedIPs: []string{"10.0.0.3/24", "20.0.0.3/24"},
},
},
}, },
{ {
name: "ProxyProtocol insecure true", name: "ProxyProtocol insecure true",
expression: "Name:foo ProxyProtocol.insecure:true", expression: "Name:foo ProxyProtocol.insecure:true",
expectedEntryPointName: "foo", expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{ expectedEntryPoint: &EntryPoint{
ForwardedHeaders: &ForwardedHeaders{}, ProxyProtocol: &ProxyProtocol{Insecure: true},
ProxyProtocol: &ProxyProtocol{Insecure: true},
}, },
}, },
{ {
@ -464,8 +256,7 @@ func TestEntryPoints_Set(t *testing.T) {
expression: "Name:foo ProxyProtocol.insecure:false", expression: "Name:foo ProxyProtocol.insecure:false",
expectedEntryPointName: "foo", expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{ expectedEntryPoint: &EntryPoint{
ForwardedHeaders: &ForwardedHeaders{}, ProxyProtocol: &ProxyProtocol{},
ProxyProtocol: &ProxyProtocol{},
}, },
}, },
{ {
@ -473,30 +264,11 @@ func TestEntryPoints_Set(t *testing.T) {
expression: "Name:foo ProxyProtocol.TrustedIPs:10.0.0.3/24,20.0.0.3/24", expression: "Name:foo ProxyProtocol.TrustedIPs:10.0.0.3/24,20.0.0.3/24",
expectedEntryPointName: "foo", expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{ expectedEntryPoint: &EntryPoint{
ForwardedHeaders: &ForwardedHeaders{},
ProxyProtocol: &ProxyProtocol{ ProxyProtocol: &ProxyProtocol{
TrustedIPs: []string{"10.0.0.3/24", "20.0.0.3/24"}, TrustedIPs: []string{"10.0.0.3/24", "20.0.0.3/24"},
}, },
}, },
}, },
{
name: "compress on",
expression: "Name:foo Compress:on",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
Compress: &Compress{},
ForwardedHeaders: &ForwardedHeaders{},
},
},
{
name: "compress true",
expression: "Name:foo Compress:true",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
Compress: &Compress{},
ForwardedHeaders: &ForwardedHeaders{},
},
},
} }
for _, test := range testCases { for _, test := range testCases {

View file

@ -1,8 +1,29 @@
package static package static
import ( import (
"errors"
"strings"
"time"
"github.com/containous/flaeg/parse" "github.com/containous/flaeg/parse"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/log"
"github.com/containous/traefik/old/provider/boltdb"
"github.com/containous/traefik/old/provider/consul"
"github.com/containous/traefik/old/provider/consulcatalog"
"github.com/containous/traefik/old/provider/docker"
"github.com/containous/traefik/old/provider/dynamodb"
"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/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/ping" "github.com/containous/traefik/ping"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/provider/file" "github.com/containous/traefik/provider/file"
"github.com/containous/traefik/tls" "github.com/containous/traefik/tls"
"github.com/containous/traefik/tracing/datadog" "github.com/containous/traefik/tracing/datadog"
@ -10,12 +31,31 @@ import (
"github.com/containous/traefik/tracing/zipkin" "github.com/containous/traefik/tracing/zipkin"
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
"github.com/elazarl/go-bindata-assetfs" "github.com/elazarl/go-bindata-assetfs"
lego "github.com/xenolf/lego/acme"
) )
// Configuration FIXME temp static configuration const (
// DefaultInternalEntryPointName the name of the default internal entry point
DefaultInternalEntryPointName = "traefik"
// DefaultGraceTimeout controls how long Traefik serves pending requests
// prior to shutting down.
DefaultGraceTimeout = 10 * time.Second
// DefaultIdleTimeout before closing an idle connection.
DefaultIdleTimeout = 180 * time.Second
// DefaultAcmeCAServer is the default ACME API endpoint
DefaultAcmeCAServer = "https://acme-v02.api.letsencrypt.org/directory"
)
// Configuration is the static configuration
type Configuration struct { type Configuration struct {
Global *Global Global *Global `description:"Global configuration options" export:"true"`
EntryPoints *EntryPoints
ServersTransport *ServersTransport `description:"Servers default transport" export:"true"`
EntryPoints EntryPoints `description:"Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key;prod/traefik.crt,prod/traefik.key'" export:"true"`
Providers *Providers `description:"Providers configuration" export:"true"`
API *API `description:"Enable api/dashboard" export:"true"` API *API `description:"Enable api/dashboard" export:"true"`
Metrics *types.Metrics `description:"Enable a metrics exporter" export:"true"` Metrics *types.Metrics `description:"Enable a metrics exporter" export:"true"`
@ -26,31 +66,24 @@ type Configuration struct {
AccessLog *types.AccessLog `description:"Access log settings" export:"true"` AccessLog *types.AccessLog `description:"Access log settings" export:"true"`
Tracing *Tracing `description:"OpenTracing configuration" export:"true"` Tracing *Tracing `description:"OpenTracing configuration" export:"true"`
File *file.Provider `description:"Enable File backend with default settings" export:"true"`
Constraints types.Constraints `description:"Filter services by constraint, matching with service tags" export:"true"`
HostResolver *HostResolverConfig `description:"Enable CNAME Flattening" export:"true"` HostResolver *HostResolverConfig `description:"Enable CNAME Flattening" export:"true"`
// TODO ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
// ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
// Retry *Retry `description:"Enable retry sending request if network error" export:"true"`
// HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"`
//
} }
// Global holds the global configuration. // Global holds the global configuration.
type Global struct { type Global struct {
Debug bool `short:"d" description:"Enable debug mode" export:"true"` Debug bool `short:"d" description:"Enable debug mode" export:"true"`
CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"` CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"`
SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"` SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"`
InsecureSkipVerify bool `description:"Disable SSL certificate verification" export:"true"` }
RootCAs tls.FilesOrContents `description:"Add cert file for self-signed certificate"`
ProvidersThrottleDuration parse.Duration `description:"Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time." export:"true"` // ServersTransport options to configure communication between Traefik and the servers
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"` type ServersTransport struct {
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"` InsecureSkipVerify bool `description:"Disable SSL certificate verification" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"` RootCAs tls.FilesOrContents `description:"Add cert file for self-signed certificate"`
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" export:"true"` MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"`
} }
// API holds the API configuration // API holds the API configuration
@ -81,20 +114,6 @@ type LifeCycle struct {
GraceTimeOut parse.Duration `description:"Duration to give active requests a chance to finish before Traefik stops"` GraceTimeOut parse.Duration `description:"Duration to give active requests a chance to finish before Traefik stops"`
} }
// EntryPoint holds the entry point configuration
type EntryPoint struct {
Address string
}
// EntryPointList holds the HTTP entry point list type.
type EntryPointList map[string]EntryPoint
// EntryPoints holds the entry points configuration.
type EntryPoints struct {
EntryPointList
Defaults []string
}
// Tracing holds the tracing configuration. // Tracing holds the tracing configuration.
type Tracing struct { type Tracing struct {
Backend string `description:"Selects the tracking backend ('jaeger','zipkin', 'datadog')." export:"true"` Backend string `description:"Selects the tracking backend ('jaeger','zipkin', 'datadog')." export:"true"`
@ -111,3 +130,276 @@ type HostResolverConfig struct {
ResolvConfig string `description:"resolv.conf used for DNS resolving" export:"true"` ResolvConfig string `description:"resolv.conf used for DNS resolving" export:"true"`
ResolvDepth int `description:"The maximal depth of DNS recursive resolving" export:"true"` ResolvDepth int `description:"The maximal depth of DNS recursive resolving" export:"true"`
} }
// Providers contains providers configuration
type Providers struct {
ProvidersThrottleDuration parse.Duration `description:"Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time." export:"true"`
Docker *docker.Provider `description:"Enable Docker backend with default settings" export:"true"`
File *file.Provider `description:"Enable File backend with default settings" export:"true"`
Marathon *marathon.Provider `description:"Enable Marathon backend with default settings" export:"true"`
Consul *consul.Provider `description:"Enable Consul backend with default settings" export:"true"`
ConsulCatalog *consulcatalog.Provider `description:"Enable Consul catalog backend with default settings" export:"true"`
Etcd *etcd.Provider `description:"Enable Etcd backend with default settings" export:"true"`
Zookeeper *zk.Provider `description:"Enable Zookeeper backend with default settings" export:"true"`
Boltdb *boltdb.Provider `description:"Enable Boltdb backend with default settings" export:"true"`
Kubernetes *kubernetes.Provider `description:"Enable Kubernetes backend with default settings" export:"true"`
Mesos *mesos.Provider `description:"Enable Mesos backend with default settings" export:"true"`
Eureka *eureka.Provider `description:"Enable Eureka backend with default settings" export:"true"`
ECS *ecs.Provider `description:"Enable ECS backend with default settings" export:"true"`
Rancher *rancher.Provider `description:"Enable Rancher backend with default settings" export:"true"`
DynamoDB *dynamodb.Provider `description:"Enable DynamoDB backend with default settings" export:"true"`
Rest *rest.Provider `description:"Enable Rest backend with default settings" export:"true"`
}
// SetEffectiveConfiguration adds missing configuration parameters derived from existing ones.
// It also takes care of maintaining backwards compatibility.
func (c *Configuration) SetEffectiveConfiguration(configFile string) {
if len(c.EntryPoints) == 0 {
c.EntryPoints = EntryPoints{
"http": &EntryPoint{
Address: ":80",
},
}
}
if (c.API != nil && c.API.EntryPoint == DefaultInternalEntryPointName) ||
(c.Ping != nil && c.Ping.EntryPoint == DefaultInternalEntryPointName) ||
(c.Metrics != nil && c.Metrics.Prometheus != nil && c.Metrics.Prometheus.EntryPoint == DefaultInternalEntryPointName) ||
(c.Providers.Rest != nil && c.Providers.Rest.EntryPoint == DefaultInternalEntryPointName) {
if _, ok := c.EntryPoints[DefaultInternalEntryPointName]; !ok {
c.EntryPoints[DefaultInternalEntryPointName] = &EntryPoint{Address: ":8080"}
}
}
for _, entryPoint := range c.EntryPoints {
if entryPoint.Transport == nil {
entryPoint.Transport = &EntryPointsTransport{}
}
// Make sure LifeCycle isn't nil to spare nil checks elsewhere.
if entryPoint.Transport.LifeCycle == nil {
entryPoint.Transport.LifeCycle = &LifeCycle{
GraceTimeOut: parse.Duration(DefaultGraceTimeout),
}
entryPoint.Transport.RespondingTimeouts = &RespondingTimeouts{
IdleTimeout: parse.Duration(DefaultIdleTimeout),
}
}
}
if c.Providers.Rancher != nil {
// Ensure backwards compatibility for now
if len(c.Providers.Rancher.AccessKey) > 0 ||
len(c.Providers.Rancher.Endpoint) > 0 ||
len(c.Providers.Rancher.SecretKey) > 0 {
if c.Providers.Rancher.API == nil {
c.Providers.Rancher.API = &rancher.APIConfiguration{
AccessKey: c.Providers.Rancher.AccessKey,
SecretKey: c.Providers.Rancher.SecretKey,
Endpoint: c.Providers.Rancher.Endpoint,
}
}
log.Warn("Deprecated configuration found: rancher.[accesskey|secretkey|endpoint]. " +
"Please use rancher.api.[accesskey|secretkey|endpoint] instead.")
}
if c.Providers.Rancher.Metadata != nil && len(c.Providers.Rancher.Metadata.Prefix) == 0 {
c.Providers.Rancher.Metadata.Prefix = "latest"
}
}
if c.Providers.File != nil {
c.Providers.File.TraefikFile = configFile
}
c.initACMEProvider()
c.initTracing()
}
func (c *Configuration) initTracing() {
if c.Tracing != nil {
switch c.Tracing.Backend {
case jaeger.Name:
if c.Tracing.Jaeger == nil {
c.Tracing.Jaeger = &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6831",
Propagation: "jaeger",
Gen128Bit: false,
}
}
if c.Tracing.Zipkin != nil {
log.Warn("Zipkin configuration will be ignored")
c.Tracing.Zipkin = nil
}
if c.Tracing.DataDog != nil {
log.Warn("DataDog configuration will be ignored")
c.Tracing.DataDog = nil
}
case zipkin.Name:
if c.Tracing.Zipkin == nil {
c.Tracing.Zipkin = &zipkin.Config{
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
SameSpan: false,
ID128Bit: true,
Debug: false,
SampleRate: 1.0,
}
}
if c.Tracing.Jaeger != nil {
log.Warn("Jaeger configuration will be ignored")
c.Tracing.Jaeger = nil
}
if c.Tracing.DataDog != nil {
log.Warn("DataDog configuration will be ignored")
c.Tracing.DataDog = nil
}
case datadog.Name:
if c.Tracing.DataDog == nil {
c.Tracing.DataDog = &datadog.Config{
LocalAgentHostPort: "localhost:8126",
GlobalTag: "",
Debug: false,
}
}
if c.Tracing.Zipkin != nil {
log.Warn("Zipkin configuration will be ignored")
c.Tracing.Zipkin = nil
}
if c.Tracing.Jaeger != nil {
log.Warn("Jaeger configuration will be ignored")
c.Tracing.Jaeger = nil
}
default:
log.Warnf("Unknown tracer %q", c.Tracing.Backend)
return
}
}
}
// FIXME handle on new configuration ACME struct
func (c *Configuration) initACMEProvider() {
if c.ACME != nil {
c.ACME.CAServer = getSafeACMECAServer(c.ACME.CAServer)
if c.ACME.DNSChallenge != nil && c.ACME.HTTPChallenge != nil {
log.Warn("Unable to use DNS challenge and HTTP challenge at the same time. Fallback to DNS challenge.")
c.ACME.HTTPChallenge = nil
}
if c.ACME.DNSChallenge != nil && c.ACME.TLSChallenge != nil {
log.Warn("Unable to use DNS challenge and TLS challenge at the same time. Fallback to DNS challenge.")
c.ACME.TLSChallenge = nil
}
if c.ACME.HTTPChallenge != nil && c.ACME.TLSChallenge != nil {
log.Warn("Unable to use HTTP challenge and TLS challenge at the same time. Fallback to TLS challenge.")
c.ACME.HTTPChallenge = nil
}
if c.ACME.OnDemand {
log.Warn("ACME.OnDemand is deprecated")
}
}
}
// InitACMEProvider create an acme provider from the ACME part of globalConfiguration
func (c *Configuration) InitACMEProvider() (*acmeprovider.Provider, error) {
if c.ACME != nil {
if len(c.ACME.Storage) == 0 {
// Delete the ACME configuration to avoid starting ACME in cluster mode
c.ACME = nil
return nil, errors.New("unable to initialize ACME provider with no storage location for the certificates")
}
provider := &acmeprovider.Provider{}
provider.Configuration = convertACMEChallenge(c.ACME)
store := acmeprovider.NewLocalStore(provider.Storage)
provider.Store = store
acme.ConvertToNewFormat(provider.Storage)
c.ACME = nil
return provider, nil
}
return nil, nil
}
// ValidateConfiguration validate that configuration is coherent
func (c *Configuration) ValidateConfiguration() {
if c.ACME != nil {
if _, ok := c.EntryPoints[c.ACME.EntryPoint]; !ok {
log.Fatalf("Unknown entrypoint %q for ACME configuration", c.ACME.EntryPoint)
} else {
if c.EntryPoints[c.ACME.EntryPoint].TLS == nil {
log.Fatalf("Entrypoint %q has no TLS configuration for ACME configuration", c.ACME.EntryPoint)
}
}
}
}
func getSafeACMECAServer(caServerSrc string) string {
if len(caServerSrc) == 0 {
return DefaultAcmeCAServer
}
if strings.HasPrefix(caServerSrc, "https://acme-v01.api.letsencrypt.org") {
caServer := strings.Replace(caServerSrc, "v01", "v02", 1)
log.Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer)
return caServer
}
if strings.HasPrefix(caServerSrc, "https://acme-staging.api.letsencrypt.org") {
caServer := strings.Replace(caServerSrc, "https://acme-staging.api.letsencrypt.org", "https://acme-staging-v02.api.letsencrypt.org", 1)
log.Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer)
return caServer
}
return caServerSrc
}
// Deprecated
func convertACMEChallenge(oldACMEChallenge *acme.ACME) *acmeprovider.Configuration {
conf := &acmeprovider.Configuration{
KeyType: oldACMEChallenge.KeyType,
OnHostRule: oldACMEChallenge.OnHostRule,
OnDemand: oldACMEChallenge.OnDemand,
Email: oldACMEChallenge.Email,
Storage: oldACMEChallenge.Storage,
ACMELogging: oldACMEChallenge.ACMELogging,
CAServer: oldACMEChallenge.CAServer,
EntryPoint: oldACMEChallenge.EntryPoint,
}
for _, domain := range oldACMEChallenge.Domains {
if domain.Main != lego.UnFqdn(domain.Main) {
log.Warnf("FQDN detected, please remove the trailing dot: %s", domain.Main)
}
for _, san := range domain.SANs {
if san != lego.UnFqdn(san) {
log.Warnf("FQDN detected, please remove the trailing dot: %s", san)
}
}
conf.Domains = append(conf.Domains, domain)
}
if oldACMEChallenge.HTTPChallenge != nil {
conf.HTTPChallenge = &acmeprovider.HTTPChallenge{
EntryPoint: oldACMEChallenge.HTTPChallenge.EntryPoint,
}
}
if oldACMEChallenge.DNSChallenge != nil {
conf.DNSChallenge = &acmeprovider.DNSChallenge{
Provider: oldACMEChallenge.DNSChallenge.Provider,
DelayBeforeCheck: oldACMEChallenge.DNSChallenge.DelayBeforeCheck,
}
}
if oldACMEChallenge.TLSChallenge != nil {
conf.TLSChallenge = &acmeprovider.TLSChallenge{}
}
return conf
}

View file

@ -53,9 +53,8 @@ func (opt Options) String() string {
// BackendConfig HealthCheck configuration for a backend // BackendConfig HealthCheck configuration for a backend
type BackendConfig struct { type BackendConfig struct {
Options Options
name string name string
disabledURLs []*url.URL disabledURLs []*url.URL
requestTimeout time.Duration
} }
func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) { func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) {

View file

@ -93,7 +93,7 @@ func cnameResolve(host string, resolvPath string) (*cnameResolv, error) {
result = append(result, tempRecord) result = append(result, tempRecord)
} }
if len(result) <= 0 { if len(result) == 0 {
return nil, nil return nil, nil
} }

View file

@ -1,9 +1,9 @@
[log]
logLevel = "ERROR" logLevel = "ERROR"
defaultEntryPoints = ["http"] filePath = "traefik.log"
checkNewVersion = false
[traefikLog] [global]
filePath = "traefik.log" checkNewVersion = false
[accessLog] [accessLog]
filePath = "access.log" filePath = "access.log"
@ -36,7 +36,8 @@ checkNewVersion = false
[api] [api]
[docker] [providers]
exposedByDefault = false [providers.docker]
domain = "docker.local" exposedByDefault = false
watch = true domain = "docker.local"
watch = true

View file

@ -1,6 +1,7 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -38,7 +39,8 @@ defaultEntryPoints = ["http", "https"]
[api] [api]
[file] [providers]
[providers.file]
[services] [services]
[services.test.loadbalancer] [services.test.loadbalancer]

View file

@ -1,6 +1,7 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -35,7 +36,8 @@ defaultEntryPoints = ["http", "https"]
[web] [web]
path="/traefik" path="/traefik"
[file] [providers]
[providers.file]
[services] [services]
[services.test.loadbalancer] [services.test.loadbalancer]

View file

@ -1,14 +1,13 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = "{{ .PortHTTP }}" address = "{{ .PortHTTP }}"
[entryPoints.https] [entryPoints.https]
address = "{{ .PortHTTPS }}" address = "{{ .PortHTTPS }}"
[entryPoints.https.tls] [entryPoints.https.tls]
[[entryPoints.https.tls.certificates]] [entryPoints.https.tls.DefaultCertificate]
certFile = "fixtures/acme/ssl/wildcard.crt" certFile = "fixtures/acme/ssl/wildcard.crt"
keyFile = "fixtures/acme/ssl/wildcard.key" keyFile = "fixtures/acme/ssl/wildcard.key"
@ -41,7 +40,8 @@ defaultEntryPoints = ["http", "https"]
[api] [api]
[file] [providers]
[providers.file]
[services] [services]
[services.test.loadbalancer] [services.test.loadbalancer]

View file

@ -1,6 +1,6 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -34,6 +34,7 @@ defaultEntryPoints = ["http", "https"]
[api] [api]
[file] [providers]
filename = "fixtures/acme/certificates.toml" [providers.file]
watch = true filename = "fixtures/acme/certificates.toml"
watch = true

View file

@ -1,6 +1,6 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -11,7 +11,7 @@ defaultEntryPoints = ["http", "https"]
[entryPoints.traefik] [entryPoints.traefik]
address = ":9000" address = ":9000"
[entryPoints.traefik.tls] [entryPoints.traefik.tls]
[[entryPoints.traefik.tls.certificates]] [entryPoints.traefik.tls.DefaultCertificate]
certFile = "fixtures/acme/ssl/wildcard.crt" certFile = "fixtures/acme/ssl/wildcard.crt"
keyFile = "fixtures/acme/ssl/wildcard.key" keyFile = "fixtures/acme/ssl/wildcard.key"

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -9,10 +8,11 @@ logLevel = "DEBUG"
address = ":8081" address = ":8081"
[consul] [providers]
endpoint = "{{.ConsulHost}}:8500" [providers.consul]
watch = true endpoint = "{{.ConsulHost}}:8500"
prefix = "traefik" watch = true
prefix = "traefik"
[api] [api]
entryPoint = "api" entryPoint = "api"

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http","https"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -11,12 +10,11 @@ logLevel = "DEBUG"
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[providers]
[providers.consul]
[consul] endpoint = "{{.ConsulHost}}:8500"
endpoint = "{{.ConsulHost}}:8500" prefix = "traefik"
prefix = "traefik" watch = true
watch = true
[api] [api]
entryPoint = "api" entryPoint = "api"

View file

@ -1,4 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[api] [api]
@ -7,6 +7,7 @@ logLevel = "DEBUG"
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
[consulCatalog] [providers]
domain = "consul.localhost" [providers.consulCatalog]
frontEndRule = "Host:{{.ServiceName}}.{{.Domain}}" domain = "consul.localhost"
frontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"

View file

@ -1,5 +1,5 @@
defaultEntryPoints = ["http"]
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -8,7 +8,8 @@ logLevel = "DEBUG"
[api] [api]
[docker] [providers]
endpoint = "{{.DockerHost}}" [providers.docker]
domain = "docker.localhost" endpoint = "{{.DockerHost}}"
exposedByDefault = false domain = "docker.localhost"
exposedByDefault = false

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -8,7 +7,8 @@ logLevel = "DEBUG"
[api] [api]
[docker] [providers]
endpoint = "{{.DockerHost}}" [providers.docker]
domain = "docker.localhost" endpoint = "{{.DockerHost}}"
exposedByDefault = true domain = "docker.localhost"
exposedByDefault = true

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -8,11 +7,12 @@ logLevel = "DEBUG"
[entryPoints.api] [entryPoints.api]
address = ":8081" address = ":8081"
[dynamodb] [providers]
accessKeyID = "key" [providers.dynamodb]
secretAccessKey = "secret" accessKeyID = "key"
endpoint = "{{.DynamoURL}}" secretAccessKey = "secret"
region = "us-east-1" endpoint = "{{.DynamoURL}}"
region = "us-east-1"
[api] [api]
entryPoint = "api" entryPoint = "api"

View file

@ -1,12 +1,12 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8080" address = ":8080"
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,12 +1,12 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8080" address = ":8080"
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -9,10 +8,11 @@ logLevel = "DEBUG"
address = ":8081" address = ":8081"
[etcd] [providers]
endpoint = "{{.EtcdHost}}:2379" [providers.etcd]
prefix = "/traefik" endpoint = "{{.EtcdHost}}:2379"
watch = true prefix = "/traefik"
watch = true
[api] [api]
entryPoint = "api" entryPoint = "api"

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http","https"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]

View file

@ -1,13 +1,13 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
[providers]
[providers.eureka]
endpoint = "http://{{.EurekaHost}}:8761/eureka"
delay = "1s"
[eureka]
endpoint = "http://{{.EurekaHost}}:8761/eureka"
delay = "1s"
[api] [api]

View file

@ -1,9 +1,8 @@
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
logLevel = "DEBUG" logLevel = "DEBUG"
[file] [providers]
[providers.file]

View file

@ -1,10 +1,10 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
[file] [providers]
directory = "fixtures/file/dir/" [providers.file]
directory = "fixtures/file/dir/"

View file

@ -1,12 +1,13 @@
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,20 +1,21 @@
defaultEntryPoints = ["https"] [serversTransport]
rootCAs = [ """{{ .CertContent }}""" ] rootCAs = [ """{{ .CertContent }}""" ]
[global]
debug = true debug = true
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[[entryPoints.https.tls.certificates]] [entryPoints.https.tls.DefaultCertificate]
certFile = """{{ .CertContent }}""" certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}""" keyFile = """{{ .KeyContent }}"""
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,5 +1,5 @@
defaultEntryPoints = ["http"]
[global]
debug = true debug = true
[entryPoints] [entryPoints]
@ -8,7 +8,8 @@ debug = true
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,18 +1,19 @@
defaultEntryPoints = ["https"]
[global]
debug = true debug = true
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[[entryPoints.https.tls.certificates]] [entryPoints.https.tls.DefaultCertificate]
certFile = """{{ .CertContent }}""" certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}""" keyFile = """{{ .KeyContent }}"""
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,21 +1,23 @@
defaultEntryPoints = ["https"]
[serversTransport]
insecureSkipVerify = true insecureSkipVerify = true
[global]
debug = true debug = true
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[[entryPoints.https.tls.certificates]] [entryPoints.https.tls.DefaultCertificate]
certFile = """{{ .CertContent }}""" certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}""" keyFile = """{{ .KeyContent }}"""
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,19 +1,20 @@
defaultEntryPoints = ["https"]
[serversTransport]
rootCAs = [ """{{ .CertContent }}""" ] rootCAs = [ """{{ .CertContent }}""" ]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[[entryPoints.https.tls.certificates]] [entryPoints.https.tls.DefaultCertificate]
certFile = """{{ .CertContent }}""" certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}""" keyFile = """{{ .KeyContent }}"""
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http1", "http2"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -10,7 +9,9 @@ logLevel = "DEBUG"
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]
service = "service1" service = "service1"

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http1", "http2"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -10,7 +9,8 @@ logLevel = "DEBUG"
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -8,7 +7,8 @@ logLevel = "DEBUG"
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -8,7 +7,8 @@ logLevel = "DEBUG"
[api] [api]
[file] [providers]
[providers.file]
[routers] [routers]
[routers.router1] [routers.router1]

View file

@ -1,7 +1,6 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
@ -9,16 +8,11 @@ defaultEntryPoints = ["https"]
[entryPoints.https.tls.ClientCA] [entryPoints.https.tls.ClientCA]
files = ["fixtures/https/clientca/ca1.crt"] files = ["fixtures/https/clientca/ca1.crt"]
optional = true optional = true
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]
@ -41,3 +35,16 @@ defaultEntryPoints = ["https"]
[[Services.service2.LoadBalancer.Servers]] [[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020" URL = "http://127.0.0.1:9020"
Weight = 1 Weight = 1
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"

View file

@ -1,23 +1,17 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[entryPoints.https.tls.ClientCA] [entryPoints.https.tls.ClientCA]
files = ["fixtures/https/clientca/ca1and2.crt"] files = ["fixtures/https/clientca/ca1and2.crt"]
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]
@ -40,3 +34,14 @@ defaultEntryPoints = ["https"]
[[Services.service2.LoadBalancer.Servers]] [[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020" URL = "http://127.0.0.1:9020"
Weight = 1 Weight = 1
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"

View file

@ -1,6 +1,6 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
@ -9,16 +9,12 @@ defaultEntryPoints = ["https"]
[entryPoints.https.tls.ClientCA] [entryPoints.https.tls.ClientCA]
files = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"] files = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"]
optional = false optional = false
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]
Service = "service1" Service = "service1"
@ -40,3 +36,15 @@ defaultEntryPoints = ["https"]
[[Services.service2.LoadBalancer.Servers]] [[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020" URL = "http://127.0.0.1:9020"
Weight = 1 Weight = 1
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"

View file

@ -1,6 +1,6 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
@ -13,7 +13,7 @@ defaultEntryPoints = ["https"]
[api] [api]
[file] [providers]
[providers.file]
fileName = "{{.DynamicConfFileName}}" fileName = "{{.DynamicConfFileName}}"
watch = true watch = true

View file

@ -1,7 +1,6 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
@ -12,7 +11,8 @@ defaultEntryPoints = ["https"]
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,6 +1,6 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http", "https"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -15,7 +15,8 @@ defaultEntryPoints = ["http", "https"]
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,21 +1,16 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]
@ -38,3 +33,14 @@ defaultEntryPoints = ["https"]
[[Services.service2.LoadBalancer.Servers]] [[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020" URL = "http://127.0.0.1:9020"
Weight = 1 Weight = 1
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"

View file

@ -1,24 +1,19 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[entryPoints.https.tls.defaultCertificate] [entryPoints.https.tls.DefaultCertificate]
certFile = "fixtures/https/snitest.com.cert" certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key" keyFile = "fixtures/https/snitest.com.key"
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/wildcard.snitest.com.cert"
keyFile = "fixtures/https/wildcard.snitest.com.key"
[[entryPoints.https.tls.certificates]]
certFile = "fixtures/https/www.snitest.com.cert"
keyFile = "fixtures/https/www.snitest.com.key"
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]
@ -35,3 +30,15 @@ defaultEntryPoints = ["https"]
[[Services.service1.LoadBalancer.Servers]] [[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010" URL = "http://127.0.0.1:9010"
Weight = 1 Weight = 1
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/wildcard.snitest.com.cert"
keyFile = "fixtures/https/wildcard.snitest.com.key"
[[tls]]
entryPoints = ["https"]
[tls.certificate]
certFile = "fixtures/https/www.snitest.com.cert"
keyFile = "fixtures/https/www.snitest.com.key"

View file

@ -1,6 +1,6 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints] [entryPoints]
[entryPoints.https] [entryPoints.https]
@ -13,7 +13,8 @@ defaultEntryPoints = ["https"]
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,7 +1,8 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"]
[serversTransport]
# Use certificate in net/internal/testcert.go # Use certificate in net/internal/testcert.go
rootCAs = [ """ rootCAs = [ """
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
@ -26,7 +27,8 @@ fblo6RBxUQ==
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,7 +1,7 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"] [serversTransport]
# Use certificate in net/internal/testcert.go # Use certificate in net/internal/testcert.go
rootCAs = [ "fixtures/https/rootcas/local.crt"] rootCAs = [ "fixtures/https/rootcas/local.crt"]
@ -11,7 +11,8 @@ rootCAs = [ "fixtures/https/rootcas/local.crt"]
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,23 +1,25 @@
defaultEntryPoints = ["http"]
keepTrailingSlash = {{ .KeepTrailingSlash }} keepTrailingSlash = {{ .KeepTrailingSlash }}
[log]
logLevel = "DEBUG"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
logLevel = "DEBUG" [providers]
[providers.file]
[file]
# rules # rules
[backends] [backends]
[backends.backend1] [backends.backend1]
[backends.backend1.servers.server1] [backends.backend1.servers.server1]
url = "http://172.17.0.2:80" url = "http://172.17.0.2:80"
weight = 1 weight = 1
[frontends] [frontends]
[frontends.frontend1] [frontends.frontend1]
backend = "backend1" backend = "backend1"
[frontends.frontend1.routes.test_1] [frontends.frontend1.routes.test_1]
rule = "Path:/test/foo" rule = "Path:/test/foo"

View file

@ -1,10 +1,13 @@
################################################################ ################################################################
# Global configuration # Global configuration
################################################################ ################################################################
traefikLogsFile = "traefik.log" [accessLog]
accessLogsFile = "access.log" filePath = "access.log"
[log]
filePath = "traefik.log"
logLevel = "ERROR" logLevel = "ERROR"
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
@ -22,7 +25,8 @@ entryPoint = "api"
################################################################ ################################################################
# File configuration backend # File configuration backend
################################################################ ################################################################
[file] [providers]
[providers.file]
################################################################ ################################################################
# rules # rules

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -11,7 +10,8 @@ logLevel = "DEBUG"
[api] [api]
entryPoint = "api" entryPoint = "api"
[marathon] [providers]
endpoint = "{{.MarathonURL}}" [providers.marathon]
watch = true endpoint = "{{.MarathonURL}}"
exposedByDefault = true watch = true
exposedByDefault = true

View file

@ -1,9 +1,9 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
logLevel = "DEBUG" [providers]
[providers.mesos]
[mesos]

View file

@ -1,19 +1,20 @@
defaultEntryPoints = ["http"] [global]
debug=true debug=true
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
[api] [api]
[docker] [providers]
endpoint = "unix:///var/run/docker.sock" [providers.docker]
watch = true endpoint = "unix:///var/run/docker.sock"
exposedByDefault = false watch = true
exposedByDefault = false
[providers.file]
[file]
[Routers] [Routers]
[Routers.router-1] [Routers.router-1]
Service = "service-test" Service = "service-test"

View file

@ -1,5 +1,5 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -9,7 +9,8 @@ defaultEntryPoints = ["http"]
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,5 +1,5 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -9,7 +9,9 @@ defaultEntryPoints = ["http"]
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]
Service = "service1" Service = "service1"

View file

@ -1,13 +1,12 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":80" address = ":80"
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,18 +1,22 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
[entryPoints.http.transport.lifeCycle]
RequestAcceptGraceTimeout = "10s"
[entryPoints.traefik] [entryPoints.traefik]
address = ":8001" address = ":8001"
[entryPoints.traefik.transport.lifeCycle]
RequestAcceptGraceTimeout = "10s"
[lifeCycle]
requestAcceptGraceTimeout = "10s"
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router] [Routers.router]
Service = "service" Service = "service"

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -8,7 +7,8 @@ logLevel = "DEBUG"
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]
@ -17,7 +17,7 @@ logLevel = "DEBUG"
Rule = "PathPrefix:/" Rule = "PathPrefix:/"
[Middlewares.retry.Retry] [Middlewares.retry.Retry]
Attempts = 3 Attempts = 3
[Services] [Services]
[Services.service1] [Services.service1]

View file

@ -1,5 +1,5 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -12,7 +12,8 @@ defaultEntryPoints = ["http"]
[api] [api]
middlewares = ["authentication"] middlewares = ["authentication"]
[middleware.authentication.basic-auth] [middlewares]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"] [middlewares.authentication.basic-auth]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
[ping] [ping]

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"

View file

@ -1,5 +1,5 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -7,10 +7,11 @@ defaultEntryPoints = ["http"]
[api] [api]
[docker] [providers]
exposedByDefault = false [providers.docker]
domain = "docker.local" exposedByDefault = false
watch = true domain = "docker.local"
watch = true
[hostResolver] [hostResolver]
cnameFlattening = true cnameFlattening = true

View file

@ -1,3 +1,4 @@
[global]
debug=true debug=true
[entryPoints] [entryPoints]
@ -6,7 +7,8 @@ debug=true
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,5 +1,5 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]

View file

@ -1,5 +1,5 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"]
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -10,4 +10,6 @@ defaultEntryPoints = ["http"]
depth=2 depth=2
[api] [api]
[docker]
[providers]
[providers.docker]

View file

@ -1,5 +1,11 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["http"]
[serversTransport.forwardingTimeouts]
dialTimeout = "300ms"
responseHeaderTimeout = "300ms"
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
@ -10,11 +16,9 @@ defaultEntryPoints = ["http"]
[api] [api]
[forwardingTimeouts]
dialTimeout = "300ms"
responseHeaderTimeout = "300ms"
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,6 +1,10 @@
[log]
logLevel = "DEBUG" logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[global]
debug = true debug = true
[serversTransport]
rootCAs = [ """{{ .RootCertContent }}""" ] rootCAs = [ """{{ .RootCertContent }}""" ]
[entryPoints] [entryPoints]
@ -13,12 +17,13 @@ rootCAs = [ """{{ .RootCertContent }}""" ]
files = [ """{{ .RootCertContent }}""" ] files = [ """{{ .RootCertContent }}""" ]
optional = false optional = false
[[entryPoints.https.tls.certificates]] [entryPoints.https.tls.DefaultCertificate]
certFile = """{{ .ServerCertContent }}""" certFile = """{{ .ServerCertContent }}"""
keyFile = """{{ .ServerKeyContent }}""" keyFile = """{{ .ServerKeyContent }}"""
[api] [api]
[docker] [providers]
endpoint = "unix:///var/run/docker.sock" [providers.docker]
watch = true endpoint = "unix:///var/run/docker.sock"
watch = true

View file

@ -1,6 +1,7 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[global]
debug = true debug = true
[api] [api]
@ -19,7 +20,8 @@ debug = true
samplingType = "const" samplingType = "const"
samplingParam = 1.0 samplingParam = 1.0
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,17 +1,16 @@
################################################################ ################################################################
# Global configuration # Global configuration
################################################################ ################################################################
[traefikLog] [log]
filePath = "traefik.log" logLevel = "DEBUG"
filePath = "traefik.log"
[global]
checkNewVersion = false
[accessLog] [accessLog]
filePath = "access.log" filePath = "access.log"
logLevel = "DEBUG"
defaultEntryPoints = ["http"]
checkNewVersion = false
[entryPoints] [entryPoints]
[entryPoints.http] [entryPoints.http]
address = ":8000" address = ":8000"
@ -19,7 +18,8 @@ checkNewVersion = false
[api] [api]
dashboard = false dashboard = false
[docker] [providers]
exposedByDefault = false [providers.docker]
domain = "docker.local" exposedByDefault = false
watch = true domain = "docker.local"
watch = true

View file

@ -1,5 +1,4 @@
defaultEntryPoints = ["http"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[entryPoints] [entryPoints]
@ -8,7 +7,8 @@ logLevel = "DEBUG"
[api] [api]
[file] [providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -1,19 +1,22 @@
defaultEntryPoints = ["wss"] [log]
logLevel = "DEBUG" logLevel = "DEBUG"
[serversTransport]
insecureSkipVerify=true insecureSkipVerify=true
[entryPoints] [entryPoints]
[entryPoints.wss] [entryPoints.wss]
address = ":8000" address = ":8000"
[entryPoints.wss.tls] [entryPoints.wss.tls]
[[entryPoints.wss.tls.certificates]] [entryPoints.wss.tls.DefaultCertificate]
certFile = "resources/tls/local.cert" certFile = "resources/tls/local.cert"
keyFile = "resources/tls/local.key" keyFile = "resources/tls/local.key"
[api] [api]
[file]
[providers]
[providers.file]
[Routers] [Routers]
[Routers.router1] [Routers.router1]

View file

@ -61,26 +61,6 @@ func (s *SimpleSuite) TestWithWebConfig(c *check.C) {
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
} }
func (s *SimpleSuite) TestDefaultEntryPoints(c *check.C) {
cmd, output := s.cmdTraefik("--debug")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.Do(500*time.Millisecond, func() error {
expected := `\"DefaultEntryPoints\":[\"http\"]`
actual := output.String()
if !strings.Contains(actual, expected) {
return fmt.Errorf("got %s, wanted %s", actual, expected)
}
return nil
})
c.Assert(err, checker.IsNil)
}
func (s *SimpleSuite) TestPrintHelp(c *check.C) { func (s *SimpleSuite) TestPrintHelp(c *check.C) {
cmd, output := s.cmdTraefik("--help") cmd, output := s.cmdTraefik("--help")
@ -180,7 +160,7 @@ func (s *SimpleSuite) TestApiOnSameEntryPoint(c *check.C) {
s.createComposeProject(c, "base") s.createComposeProject(c, "base")
s.composeProject.Start(c) s.composeProject.Start(c)
cmd, output := s.traefikCmd("--defaultEntryPoints=http", "--entryPoints=Name:http Address::8000", "--api.entryPoint=http", "--debug", "--docker") cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--api.entryPoint=http", "--global.debug", "--providers.docker")
defer output(c) defer output(c)
err := cmd.Start() err := cmd.Start()
@ -264,7 +244,7 @@ func (s *SimpleSuite) TestDefaultEntrypointHTTP(c *check.C) {
s.createComposeProject(c, "base") s.createComposeProject(c, "base")
s.composeProject.Start(c) s.composeProject.Start(c)
cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--debug", "--docker", "--api") cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--global.debug", "--providers.docker", "--api")
defer output(c) defer output(c)
err := cmd.Start() err := cmd.Start()
@ -284,7 +264,7 @@ func (s *SimpleSuite) TestWithUnexistingEntrypoint(c *check.C) {
s.createComposeProject(c, "base") s.createComposeProject(c, "base")
s.composeProject.Start(c) s.composeProject.Start(c)
cmd, output := s.traefikCmd("--defaultEntryPoints=https,http", "--entryPoints=Name:http Address::8000", "--debug", "--docker", "--api") cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--global.debug", "--providers.docker", "--api")
defer output(c) defer output(c)
err := cmd.Start() err := cmd.Start()
@ -304,7 +284,7 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntrypoint(c *check.C) {
s.createComposeProject(c, "base") s.createComposeProject(c, "base")
s.composeProject.Start(c) s.composeProject.Start(c)
cmd, output := s.traefikCmd("--defaultEntryPoints=http", "--entryPoints=Name:http Address::8000", "--api", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--docker", "--debug") cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--api", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--docker", "--global.debug")
defer output(c) defer output(c)
err := cmd.Start() err := cmd.Start()

View file

@ -49,7 +49,7 @@ func (s *WebsocketSuite) TestBase(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -99,7 +99,7 @@ func (s *WebsocketSuite) TestWrongOrigin(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -149,7 +149,7 @@ func (s *WebsocketSuite) TestOrigin(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -210,7 +210,7 @@ func (s *WebsocketSuite) TestWrongOriginIgnoredByServer(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -268,7 +268,7 @@ func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -331,7 +331,7 @@ func (s *WebsocketSuite) TestBasicAuth(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -375,7 +375,7 @@ func (s *WebsocketSuite) TestSpecificResponseFromBackend(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -421,7 +421,7 @@ func (s *WebsocketSuite) TestURLWithURLEncodedChar(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -476,7 +476,7 @@ func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug", "--accesslog") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug", "--accesslog")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()
@ -535,7 +535,7 @@ func (s *WebsocketSuite) TestHeaderAreForwared(c *check.C) {
}) })
defer os.Remove(file) defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug") cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c) defer display(c)
err := cmd.Start() err := cmd.Start()

View file

@ -60,7 +60,7 @@ func (ip *Checker) IsAuthorized(addr string) error {
// Contains checks if provided address is in the trusted IPs // Contains checks if provided address is in the trusted IPs
func (ip *Checker) Contains(addr string) (bool, error) { func (ip *Checker) Contains(addr string) (bool, error) {
if len(addr) <= 0 { if len(addr) == 0 {
return false, errors.New("empty IP address") return false, errors.New("empty IP address")
} }

View file

@ -94,7 +94,7 @@ func cnameResolve(ctx context.Context, host string, resolvPath string) (*cnameRe
result = append(result, tempRecord) result = append(result, tempRecord)
} }
if len(result) <= 0 { if len(result) == 0 {
return nil, nil return nil, nil
} }

View file

@ -29,9 +29,9 @@ import (
"github.com/containous/traefik/old/provider/rancher" "github.com/containous/traefik/old/provider/rancher"
"github.com/containous/traefik/old/provider/rest" "github.com/containous/traefik/old/provider/rest"
"github.com/containous/traefik/old/provider/zk" "github.com/containous/traefik/old/provider/zk"
"github.com/containous/traefik/old/tls"
"github.com/containous/traefik/old/types" "github.com/containous/traefik/old/types"
acmeprovider "github.com/containous/traefik/provider/acme" acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/tls"
newtypes "github.com/containous/traefik/types" newtypes "github.com/containous/traefik/types"
"github.com/pkg/errors" "github.com/pkg/errors"
lego "github.com/xenolf/lego/acme" lego "github.com/xenolf/lego/acme"

View file

@ -1,224 +0,0 @@
package configuration
import (
"testing"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/old/middlewares/tracing"
"github.com/containous/traefik/old/middlewares/tracing/jaeger"
"github.com/containous/traefik/old/middlewares/tracing/zipkin"
"github.com/containous/traefik/old/provider"
acmeprovider "github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/provider/file"
"github.com/stretchr/testify/assert"
)
const defaultConfigFile = "traefik.toml"
func TestSetEffectiveConfigurationFileProviderFilename(t *testing.T) {
testCases := []struct {
desc string
fileProvider *file.Provider
wantFileProviderFilename string
wantFileProviderTraefikFile string
}{
{
desc: "no filename for file provider given",
fileProvider: &file.Provider{},
wantFileProviderFilename: "",
wantFileProviderTraefikFile: defaultConfigFile,
},
{
desc: "filename for file provider given",
fileProvider: &file.Provider{BaseProvider: provider.BaseProvider{Filename: "other.toml"}},
wantFileProviderFilename: "other.toml",
wantFileProviderTraefikFile: defaultConfigFile,
},
{
desc: "directory for file provider given",
fileProvider: &file.Provider{Directory: "/"},
wantFileProviderFilename: "",
wantFileProviderTraefikFile: defaultConfigFile,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
gc := &GlobalConfiguration{
File: test.fileProvider,
}
gc.SetEffectiveConfiguration(defaultConfigFile)
assert.Equal(t, test.wantFileProviderFilename, gc.File.Filename)
assert.Equal(t, test.wantFileProviderTraefikFile, gc.File.TraefikFile)
})
}
}
func TestSetEffectiveConfigurationTracing(t *testing.T) {
testCases := []struct {
desc string
tracing *tracing.Tracing
expected *tracing.Tracing
}{
{
desc: "no tracing configuration",
tracing: &tracing.Tracing{},
expected: &tracing.Tracing{},
},
{
desc: "tracing bad backend name",
tracing: &tracing.Tracing{
Backend: "powpow",
},
expected: &tracing.Tracing{
Backend: "powpow",
},
},
{
desc: "tracing jaeger backend name",
tracing: &tracing.Tracing{
Backend: "jaeger",
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
SameSpan: false,
ID128Bit: true,
Debug: false,
},
},
expected: &tracing.Tracing{
Backend: "jaeger",
Jaeger: &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6831",
Propagation: "jaeger",
Gen128Bit: false,
},
Zipkin: nil,
},
},
{
desc: "tracing zipkin backend name",
tracing: &tracing.Tracing{
Backend: "zipkin",
Jaeger: &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6831",
},
},
expected: &tracing.Tracing{
Backend: "zipkin",
Jaeger: nil,
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
SameSpan: false,
ID128Bit: true,
Debug: false,
SampleRate: 1.0,
},
},
},
{
desc: "tracing zipkin backend name value override",
tracing: &tracing.Tracing{
Backend: "zipkin",
Jaeger: &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6831",
},
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://powpow:9411/api/v1/spans",
SameSpan: true,
ID128Bit: true,
Debug: true,
SampleRate: 0.02,
},
},
expected: &tracing.Tracing{
Backend: "zipkin",
Jaeger: nil,
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://powpow:9411/api/v1/spans",
SameSpan: true,
ID128Bit: true,
Debug: true,
SampleRate: 0.02,
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
gc := &GlobalConfiguration{
Tracing: test.tracing,
}
gc.SetEffectiveConfiguration(defaultConfigFile)
assert.Equal(t, test.expected, gc.Tracing)
})
}
}
func TestInitACMEProvider(t *testing.T) {
testCases := []struct {
desc string
acmeConfiguration *acme.ACME
expectedConfiguration *acmeprovider.Provider
noError bool
}{
{
desc: "No ACME configuration",
acmeConfiguration: nil,
expectedConfiguration: nil,
noError: true,
},
{
desc: "ACME configuration with storage",
acmeConfiguration: &acme.ACME{Storage: "foo/acme.json"},
expectedConfiguration: &acmeprovider.Provider{Configuration: &acmeprovider.Configuration{Storage: "foo/acme.json"}},
noError: true,
},
{
desc: "ACME configuration with no storage",
acmeConfiguration: &acme.ACME{},
expectedConfiguration: nil,
noError: false,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
gc := &GlobalConfiguration{
ACME: test.acmeConfiguration,
}
configuration, err := gc.InitACMEProvider()
assert.True(t, (err == nil) == test.noError)
if test.expectedConfiguration == nil {
assert.Nil(t, configuration)
} else {
assert.Equal(t, test.expectedConfiguration.Storage, configuration.Storage)
}
})
}
}

View file

@ -1,33 +1,30 @@
package static package configuration
import ( import (
oldapi "github.com/containous/traefik/old/api" "github.com/containous/traefik/config/static"
"github.com/containous/traefik/old/configuration" "github.com/containous/traefik/old/api"
oldtracing "github.com/containous/traefik/old/middlewares/tracing" "github.com/containous/traefik/old/middlewares/tracing"
oldfile "github.com/containous/traefik/old/provider/file" "github.com/containous/traefik/old/provider/file"
oldtypes "github.com/containous/traefik/old/types" "github.com/containous/traefik/old/types"
"github.com/containous/traefik/ping" "github.com/containous/traefik/ping"
"github.com/containous/traefik/provider" "github.com/containous/traefik/provider"
"github.com/containous/traefik/provider/file" file2 "github.com/containous/traefik/provider/file"
"github.com/containous/traefik/tracing/datadog" "github.com/containous/traefik/tracing/datadog"
"github.com/containous/traefik/tracing/jaeger" "github.com/containous/traefik/tracing/jaeger"
"github.com/containous/traefik/tracing/zipkin" "github.com/containous/traefik/tracing/zipkin"
"github.com/containous/traefik/types" types2 "github.com/containous/traefik/types"
) )
// ConvertStaticConf FIXME sugar // ConvertStaticConf FIXME sugar
// Deprecated // Deprecated
func ConvertStaticConf(globalConfiguration configuration.GlobalConfiguration) Configuration { func ConvertStaticConf(globalConfiguration GlobalConfiguration) static.Configuration {
staticConfiguration := Configuration{} staticConfiguration := static.Configuration{}
staticConfiguration.EntryPoints = &EntryPoints{ staticConfiguration.EntryPoints = make(static.EntryPoints)
EntryPointList: make(EntryPointList),
Defaults: globalConfiguration.DefaultEntryPoints,
}
if globalConfiguration.EntryPoints != nil { if globalConfiguration.EntryPoints != nil {
for name, ep := range globalConfiguration.EntryPoints { for name, ep := range globalConfiguration.EntryPoints {
staticConfiguration.EntryPoints.EntryPointList[name] = EntryPoint{ staticConfiguration.EntryPoints[name] = &static.EntryPoint{
Address: ep.Address, Address: ep.Address,
} }
} }
@ -41,8 +38,7 @@ func ConvertStaticConf(globalConfiguration configuration.GlobalConfiguration) Co
} }
staticConfiguration.API = convertAPI(globalConfiguration.API) staticConfiguration.API = convertAPI(globalConfiguration.API)
staticConfiguration.Constraints = convertConstraints(globalConfiguration.Constraints) staticConfiguration.Providers.File = convertFile(globalConfiguration.File)
staticConfiguration.File = convertFile(globalConfiguration.File)
staticConfiguration.Metrics = ConvertMetrics(globalConfiguration.Metrics) staticConfiguration.Metrics = ConvertMetrics(globalConfiguration.Metrics)
staticConfiguration.AccessLog = ConvertAccessLog(globalConfiguration.AccessLog) staticConfiguration.AccessLog = ConvertAccessLog(globalConfiguration.AccessLog)
staticConfiguration.Tracing = ConvertTracing(globalConfiguration.Tracing) staticConfiguration.Tracing = ConvertTracing(globalConfiguration.Tracing)
@ -53,35 +49,35 @@ func ConvertStaticConf(globalConfiguration configuration.GlobalConfiguration) Co
// ConvertAccessLog FIXME sugar // ConvertAccessLog FIXME sugar
// Deprecated // Deprecated
func ConvertAccessLog(old *oldtypes.AccessLog) *types.AccessLog { func ConvertAccessLog(old *types.AccessLog) *types2.AccessLog {
if old == nil { if old == nil {
return nil return nil
} }
accessLog := &types.AccessLog{ accessLog := &types2.AccessLog{
FilePath: old.FilePath, FilePath: old.FilePath,
Format: old.Format, Format: old.Format,
BufferingSize: old.BufferingSize, BufferingSize: old.BufferingSize,
} }
if old.Filters != nil { if old.Filters != nil {
accessLog.Filters = &types.AccessLogFilters{ accessLog.Filters = &types2.AccessLogFilters{
StatusCodes: types.StatusCodes(old.Filters.StatusCodes), StatusCodes: types2.StatusCodes(old.Filters.StatusCodes),
RetryAttempts: old.Filters.RetryAttempts, RetryAttempts: old.Filters.RetryAttempts,
MinDuration: old.Filters.MinDuration, MinDuration: old.Filters.MinDuration,
} }
} }
if old.Fields != nil { if old.Fields != nil {
accessLog.Fields = &types.AccessLogFields{ accessLog.Fields = &types2.AccessLogFields{
DefaultMode: old.Fields.DefaultMode, DefaultMode: old.Fields.DefaultMode,
Names: types.FieldNames(old.Fields.Names), Names: types2.FieldNames(old.Fields.Names),
} }
if old.Fields.Headers != nil { if old.Fields.Headers != nil {
accessLog.Fields.Headers = &types.FieldHeaders{ accessLog.Fields.Headers = &types2.FieldHeaders{
DefaultMode: old.Fields.Headers.DefaultMode, DefaultMode: old.Fields.Headers.DefaultMode,
Names: types.FieldHeaderNames(old.Fields.Headers.Names), Names: types2.FieldHeaderNames(old.Fields.Headers.Names),
} }
} }
} }
@ -91,35 +87,35 @@ func ConvertAccessLog(old *oldtypes.AccessLog) *types.AccessLog {
// ConvertMetrics FIXME sugar // ConvertMetrics FIXME sugar
// Deprecated // Deprecated
func ConvertMetrics(old *oldtypes.Metrics) *types.Metrics { func ConvertMetrics(old *types.Metrics) *types2.Metrics {
if old == nil { if old == nil {
return nil return nil
} }
metrics := &types.Metrics{} metrics := &types2.Metrics{}
if old.Prometheus != nil { if old.Prometheus != nil {
metrics.Prometheus = &types.Prometheus{ metrics.Prometheus = &types2.Prometheus{
EntryPoint: old.Prometheus.EntryPoint, EntryPoint: old.Prometheus.EntryPoint,
Buckets: types.Buckets(old.Prometheus.Buckets), Buckets: types2.Buckets(old.Prometheus.Buckets),
} }
} }
if old.Datadog != nil { if old.Datadog != nil {
metrics.Datadog = &types.Datadog{ metrics.Datadog = &types2.Datadog{
Address: old.Datadog.Address, Address: old.Datadog.Address,
PushInterval: old.Datadog.PushInterval, PushInterval: old.Datadog.PushInterval,
} }
} }
if old.StatsD != nil { if old.StatsD != nil {
metrics.StatsD = &types.Statsd{ metrics.StatsD = &types2.Statsd{
Address: old.StatsD.Address, Address: old.StatsD.Address,
PushInterval: old.StatsD.PushInterval, PushInterval: old.StatsD.PushInterval,
} }
} }
if old.InfluxDB != nil { if old.InfluxDB != nil {
metrics.InfluxDB = &types.InfluxDB{ metrics.InfluxDB = &types2.InfluxDB{
Address: old.InfluxDB.Address, Address: old.InfluxDB.Address,
Protocol: old.InfluxDB.Protocol, Protocol: old.InfluxDB.Protocol,
PushInterval: old.InfluxDB.PushInterval, PushInterval: old.InfluxDB.PushInterval,
@ -135,12 +131,12 @@ func ConvertMetrics(old *oldtypes.Metrics) *types.Metrics {
// ConvertTracing FIXME sugar // ConvertTracing FIXME sugar
// Deprecated // Deprecated
func ConvertTracing(old *oldtracing.Tracing) *Tracing { func ConvertTracing(old *tracing.Tracing) *static.Tracing {
if old == nil { if old == nil {
return nil return nil
} }
tra := &Tracing{ tra := &static.Tracing{
Backend: old.Backend, Backend: old.Backend,
ServiceName: old.ServiceName, ServiceName: old.ServiceName,
SpanNameLimit: old.SpanNameLimit, SpanNameLimit: old.SpanNameLimit,
@ -177,19 +173,19 @@ func ConvertTracing(old *oldtracing.Tracing) *Tracing {
return tra return tra
} }
func convertAPI(old *oldapi.Handler) *API { func convertAPI(old *api.Handler) *static.API {
if old == nil { if old == nil {
return nil return nil
} }
api := &API{ api := &static.API{
EntryPoint: old.EntryPoint, EntryPoint: old.EntryPoint,
Dashboard: old.Dashboard, Dashboard: old.Dashboard,
DashboardAssets: old.DashboardAssets, DashboardAssets: old.DashboardAssets,
} }
if old.Statistics != nil { if old.Statistics != nil {
api.Statistics = &types.Statistics{ api.Statistics = &types2.Statistics{
RecentErrors: old.Statistics.RecentErrors, RecentErrors: old.Statistics.RecentErrors,
} }
} }
@ -197,10 +193,10 @@ func convertAPI(old *oldapi.Handler) *API {
return api return api
} }
func convertConstraints(oldConstraints oldtypes.Constraints) types.Constraints { func convertConstraints(oldConstraints types.Constraints) types2.Constraints {
constraints := types.Constraints{} constraints := types2.Constraints{}
for _, value := range oldConstraints { for _, value := range oldConstraints {
constraint := &types.Constraint{ constraint := &types2.Constraint{
Key: value.Key, Key: value.Key,
MustMatch: value.MustMatch, MustMatch: value.MustMatch,
Regex: value.Regex, Regex: value.Regex,
@ -211,12 +207,12 @@ func convertConstraints(oldConstraints oldtypes.Constraints) types.Constraints {
return constraints return constraints
} }
func convertFile(old *oldfile.Provider) *file.Provider { func convertFile(old *file.Provider) *file2.Provider {
if old == nil { if old == nil {
return nil return nil
} }
f := &file.Provider{ f := &file2.Provider{
BaseProvider: provider.BaseProvider{ BaseProvider: provider.BaseProvider{
Watch: old.Watch, Watch: old.Watch,
Filename: old.Filename, Filename: old.Filename,
@ -233,12 +229,12 @@ func convertFile(old *oldfile.Provider) *file.Provider {
// ConvertHostResolverConfig FIXME // ConvertHostResolverConfig FIXME
// Deprecated // Deprecated
func ConvertHostResolverConfig(oldconfig *configuration.HostResolverConfig) *HostResolverConfig { func ConvertHostResolverConfig(oldconfig *HostResolverConfig) *static.HostResolverConfig {
if oldconfig == nil { if oldconfig == nil {
return nil return nil
} }
return &HostResolverConfig{ return &static.HostResolverConfig{
CnameFlattening: oldconfig.CnameFlattening, CnameFlattening: oldconfig.CnameFlattening,
ResolvConfig: oldconfig.ResolvConfig, ResolvConfig: oldconfig.ResolvConfig,
ResolvDepth: oldconfig.ResolvDepth, ResolvDepth: oldconfig.ResolvDepth,

View file

@ -6,8 +6,8 @@ import (
"strings" "strings"
"github.com/containous/traefik/old/log" "github.com/containous/traefik/old/log"
"github.com/containous/traefik/old/tls"
"github.com/containous/traefik/old/types" "github.com/containous/traefik/old/types"
"github.com/containous/traefik/tls"
) )
// EntryPoint holds an entry point configuration of the reverse proxy (ip, port, TLS...) // EntryPoint holds an entry point configuration of the reverse proxy (ip, port, TLS...)

View file

@ -1,151 +0,0 @@
package router
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/containous/mux"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/old/api"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/log"
"github.com/containous/traefik/old/ping"
acmeprovider "github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/safe"
"github.com/stretchr/testify/assert"
"github.com/urfave/negroni"
)
func TestNewInternalRouterAggregatorWithAuth(t *testing.T) {
currentConfiguration := &safe.Safe{}
currentConfiguration.Set(types.Configurations{})
globalConfiguration := configuration.GlobalConfiguration{
API: &api.Handler{
EntryPoint: "traefik",
CurrentConfigurations: currentConfiguration,
},
Ping: &ping.Handler{
EntryPoint: "traefik",
},
ACME: &acme.ACME{
HTTPChallenge: &acmeprovider.HTTPChallenge{
EntryPoint: "traefik",
},
},
EntryPoints: configuration.EntryPoints{
"traefik": &configuration.EntryPoint{
Auth: &types.Auth{
Basic: &types.Basic{
Users: types.Users{"test:test"},
},
},
},
},
}
testCases := []struct {
desc string
testedURL string
expectedStatusCode int
}{
{
desc: "Wrong url",
testedURL: "/wrong",
expectedStatusCode: 502,
},
{
desc: "Ping without auth",
testedURL: "/ping",
expectedStatusCode: 200,
},
{
desc: "acme without auth",
testedURL: "/.well-known/acme-challenge/token",
expectedStatusCode: 404,
},
{
desc: "api with auth",
testedURL: "/api",
expectedStatusCode: 401,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
router := NewInternalRouterAggregator(globalConfiguration, "traefik")
internalMuxRouter := mux.NewRouter()
router.AddRoutes(internalMuxRouter)
internalMuxRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadGateway)
})
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, test.testedURL, nil)
internalMuxRouter.ServeHTTP(recorder, request)
assert.Equal(t, test.expectedStatusCode, recorder.Code)
})
}
}
type MockInternalRouterFunc func(systemRouter *mux.Router)
func (m MockInternalRouterFunc) AddRoutes(systemRouter *mux.Router) {
m(systemRouter)
}
func TestWithMiddleware(t *testing.T) {
router := WithMiddleware{
router: MockInternalRouterFunc(func(systemRouter *mux.Router) {
systemRouter.Handle("/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if _, err := w.Write([]byte("router")); err != nil {
log.Error(err)
}
}))
}),
routerMiddlewares: []negroni.Handler{
negroni.HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if _, err := rw.Write([]byte("before middleware1|")); err != nil {
log.Error(err)
}
next.ServeHTTP(rw, r)
if _, err := rw.Write([]byte("|after middleware1")); err != nil {
log.Error(err)
}
}),
negroni.HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if _, err := rw.Write([]byte("before middleware2|")); err != nil {
log.Error(err)
}
next.ServeHTTP(rw, r)
if _, err := rw.Write([]byte("|after middleware2")); err != nil {
log.Error(err)
}
}),
},
}
internalMuxRouter := mux.NewRouter()
router.AddRoutes(internalMuxRouter)
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, "/test", nil)
internalMuxRouter.ServeHTTP(recorder, request)
obtained := recorder.Body.String()
assert.Equal(t, "before middleware1|before middleware2|router|after middleware2|after middleware1", obtained)
}

View file

@ -1,79 +0,0 @@
package log
import (
"io/ioutil"
"os"
"strings"
"testing"
"time"
)
func TestLogRotation(t *testing.T) {
tempDir, err := ioutil.TempDir("", "traefik_")
if err != nil {
t.Fatalf("Error setting up temporary directory: %s", err)
}
fileName := tempDir + "traefik.log"
if err := OpenFile(fileName); err != nil {
t.Fatalf("Error opening temporary file %s: %s", fileName, err)
}
defer CloseFile()
rotatedFileName := fileName + ".rotated"
iterations := 20
halfDone := make(chan bool)
writeDone := make(chan bool)
go func() {
for i := 0; i < iterations; i++ {
Println("Test log line")
if i == iterations/2 {
halfDone <- true
}
}
writeDone <- true
}()
<-halfDone
err = os.Rename(fileName, rotatedFileName)
if err != nil {
t.Fatalf("Error renaming file: %s", err)
}
err = RotateFile()
if err != nil {
t.Fatalf("Error rotating file: %s", err)
}
select {
case <-writeDone:
gotLineCount := lineCount(t, fileName) + lineCount(t, rotatedFileName)
if iterations != gotLineCount {
t.Errorf("Wanted %d written log lines, got %d", iterations, gotLineCount)
}
case <-time.After(500 * time.Millisecond):
t.Fatalf("test timed out")
}
close(halfDone)
close(writeDone)
}
func lineCount(t *testing.T, fileName string) int {
t.Helper()
fileContents, err := ioutil.ReadFile(fileName)
if err != nil {
t.Fatalf("Error reading from file %s: %s", fileName, err)
}
count := 0
for _, line := range strings.Split(string(fileContents), "\n") {
if strings.TrimSpace(line) == "" {
continue
}
count++
}
return count
}

View file

@ -1,182 +0,0 @@
package redirect
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/testhelpers"
"github.com/containous/traefik/tls"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewEntryPointHandler(t *testing.T) {
testCases := []struct {
desc string
entryPoint *configuration.EntryPoint
permanent bool
url string
expectedURL string
expectedStatus int
errorExpected bool
}{
{
desc: "HTTP to HTTPS",
entryPoint: &configuration.EntryPoint{Address: ":443", TLS: &tls.TLS{}},
url: "http://foo:80",
expectedURL: "https://foo:443",
expectedStatus: http.StatusFound,
},
{
desc: "HTTPS to HTTP",
entryPoint: &configuration.EntryPoint{Address: ":80"},
url: "https://foo:443",
expectedURL: "http://foo:80",
expectedStatus: http.StatusFound,
},
{
desc: "HTTP to HTTP",
entryPoint: &configuration.EntryPoint{Address: ":88"},
url: "http://foo:80",
expectedURL: "http://foo:88",
expectedStatus: http.StatusFound,
},
{
desc: "HTTP to HTTPS permanent",
entryPoint: &configuration.EntryPoint{Address: ":443", TLS: &tls.TLS{}},
permanent: true,
url: "http://foo:80",
expectedURL: "https://foo:443",
expectedStatus: http.StatusMovedPermanently,
},
{
desc: "HTTPS to HTTP permanent",
entryPoint: &configuration.EntryPoint{Address: ":80"},
permanent: true,
url: "https://foo:443",
expectedURL: "http://foo:80",
expectedStatus: http.StatusMovedPermanently,
},
{
desc: "invalid address",
entryPoint: &configuration.EntryPoint{Address: ":foo", TLS: &tls.TLS{}},
url: "http://foo:80",
errorExpected: true,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
handler, err := NewEntryPointHandler(test.entryPoint, test.permanent)
if test.errorExpected {
require.Error(t, err)
} else {
require.NoError(t, err)
recorder := httptest.NewRecorder()
r := testhelpers.MustNewRequest(http.MethodGet, test.url, nil)
handler.ServeHTTP(recorder, r, nil)
location, err := recorder.Result().Location()
require.NoError(t, err)
assert.Equal(t, test.expectedURL, location.String())
assert.Equal(t, test.expectedStatus, recorder.Code)
}
})
}
}
func TestNewRegexHandler(t *testing.T) {
testCases := []struct {
desc string
regex string
replacement string
permanent bool
url string
expectedURL string
expectedStatus int
errorExpected bool
}{
{
desc: "simple redirection",
regex: `^(?:http?:\/\/)(foo)(\.com)(:\d+)(.*)$`,
replacement: "https://${1}bar$2:443$4",
url: "http://foo.com:80",
expectedURL: "https://foobar.com:443",
expectedStatus: http.StatusFound,
},
{
desc: "use request header",
regex: `^(?:http?:\/\/)(foo)(\.com)(:\d+)(.*)$`,
replacement: `https://${1}{{ .Request.Header.Get "X-Foo" }}$2:443$4`,
url: "http://foo.com:80",
expectedURL: "https://foobar.com:443",
expectedStatus: http.StatusFound,
},
{
desc: "URL doesn't match regex",
regex: `^(?:http?:\/\/)(foo)(\.com)(:\d+)(.*)$`,
replacement: "https://${1}bar$2:443$4",
url: "http://bar.com:80",
expectedStatus: http.StatusOK,
},
{
desc: "invalid rewritten URL",
regex: `^(.*)$`,
replacement: "http://192.168.0.%31/",
url: "http://foo.com:80",
expectedStatus: http.StatusBadGateway,
},
{
desc: "invalid regex",
regex: `^(.*`,
replacement: "$1",
url: "http://foo.com:80",
errorExpected: true,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
handler, err := NewRegexHandler(test.regex, test.replacement, test.permanent)
if test.errorExpected {
require.Nil(t, handler)
require.Error(t, err)
} else {
require.NotNil(t, handler)
require.NoError(t, err)
recorder := httptest.NewRecorder()
r := testhelpers.MustNewRequest(http.MethodGet, test.url, nil)
r.Header.Set("X-Foo", "bar")
next := func(rw http.ResponseWriter, req *http.Request) {}
handler.ServeHTTP(recorder, r, next)
if test.expectedStatus == http.StatusMovedPermanently || test.expectedStatus == http.StatusFound {
assert.Equal(t, test.expectedStatus, recorder.Code)
location, err := recorder.Result().Location()
require.NoError(t, err)
assert.Equal(t, test.expectedURL, location.String())
} else {
assert.Equal(t, test.expectedStatus, recorder.Code)
location, err := recorder.Result().Location()
require.Errorf(t, err, "Location %v", location)
}
}
})
}
}

View file

@ -1,684 +0,0 @@
package acme
import (
"crypto/tls"
"testing"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/safe"
traefiktls "github.com/containous/traefik/tls"
"github.com/stretchr/testify/assert"
"github.com/xenolf/lego/acme"
)
func TestGetUncheckedCertificates(t *testing.T) {
wildcardMap := make(map[string]*tls.Certificate)
wildcardMap["*.traefik.wtf"] = &tls.Certificate{}
wildcardSafe := &safe.Safe{}
wildcardSafe.Set(wildcardMap)
domainMap := make(map[string]*tls.Certificate)
domainMap["traefik.wtf"] = &tls.Certificate{}
domainSafe := &safe.Safe{}
domainSafe.Set(domainMap)
testCases := []struct {
desc string
dynamicCerts *safe.Safe
staticCerts *safe.Safe
resolvingDomains map[string]struct{}
acmeCertificates []*Certificate
domains []string
expectedDomains []string
}{
{
desc: "wildcard to generate",
domains: []string{"*.traefik.wtf"},
expectedDomains: []string{"*.traefik.wtf"},
},
{
desc: "wildcard already exists in dynamic certificates",
domains: []string{"*.traefik.wtf"},
dynamicCerts: wildcardSafe,
expectedDomains: nil,
},
{
desc: "wildcard already exists in static certificates",
domains: []string{"*.traefik.wtf"},
staticCerts: wildcardSafe,
expectedDomains: nil,
},
{
desc: "wildcard already exists in ACME certificates",
domains: []string{"*.traefik.wtf"},
acmeCertificates: []*Certificate{
{
Domain: types.Domain{Main: "*.traefik.wtf"},
},
},
expectedDomains: nil,
},
{
desc: "domain CN and SANs to generate",
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
expectedDomains: []string{"traefik.wtf", "foo.traefik.wtf"},
},
{
desc: "domain CN already exists in dynamic certificates and SANs to generate",
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
dynamicCerts: domainSafe,
expectedDomains: []string{"foo.traefik.wtf"},
},
{
desc: "domain CN already exists in static certificates and SANs to generate",
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
staticCerts: domainSafe,
expectedDomains: []string{"foo.traefik.wtf"},
},
{
desc: "domain CN already exists in ACME certificates and SANs to generate",
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
acmeCertificates: []*Certificate{
{
Domain: types.Domain{Main: "traefik.wtf"},
},
},
expectedDomains: []string{"foo.traefik.wtf"},
},
{
desc: "domain already exists in dynamic certificates",
domains: []string{"traefik.wtf"},
dynamicCerts: domainSafe,
expectedDomains: nil,
},
{
desc: "domain already exists in static certificates",
domains: []string{"traefik.wtf"},
staticCerts: domainSafe,
expectedDomains: nil,
},
{
desc: "domain already exists in ACME certificates",
domains: []string{"traefik.wtf"},
acmeCertificates: []*Certificate{
{
Domain: types.Domain{Main: "traefik.wtf"},
},
},
expectedDomains: nil,
},
{
desc: "domain matched by wildcard in dynamic certificates",
domains: []string{"who.traefik.wtf", "foo.traefik.wtf"},
dynamicCerts: wildcardSafe,
expectedDomains: nil,
},
{
desc: "domain matched by wildcard in static certificates",
domains: []string{"who.traefik.wtf", "foo.traefik.wtf"},
staticCerts: wildcardSafe,
expectedDomains: nil,
},
{
desc: "domain matched by wildcard in ACME certificates",
domains: []string{"who.traefik.wtf", "foo.traefik.wtf"},
acmeCertificates: []*Certificate{
{
Domain: types.Domain{Main: "*.traefik.wtf"},
},
},
expectedDomains: nil,
},
{
desc: "root domain with wildcard in ACME certificates",
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
acmeCertificates: []*Certificate{
{
Domain: types.Domain{Main: "*.traefik.wtf"},
},
},
expectedDomains: []string{"traefik.wtf"},
},
{
desc: "all domains already managed by ACME",
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
resolvingDomains: map[string]struct{}{
"traefik.wtf": {},
"foo.traefik.wtf": {},
},
expectedDomains: []string{},
},
{
desc: "one domain already managed by ACME",
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
resolvingDomains: map[string]struct{}{
"traefik.wtf": {},
},
expectedDomains: []string{"foo.traefik.wtf"},
},
{
desc: "wildcard domain already managed by ACME checks the domains",
domains: []string{"bar.traefik.wtf", "foo.traefik.wtf"},
resolvingDomains: map[string]struct{}{
"*.traefik.wtf": {},
},
expectedDomains: []string{},
},
{
desc: "wildcard domain already managed by ACME checks domains and another domain checks one other domain, one domain still unchecked",
domains: []string{"traefik.wtf", "bar.traefik.wtf", "foo.traefik.wtf", "acme.wtf"},
resolvingDomains: map[string]struct{}{
"*.traefik.wtf": {},
"traefik.wtf": {},
},
expectedDomains: []string{"acme.wtf"},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
if test.resolvingDomains == nil {
test.resolvingDomains = make(map[string]struct{})
}
acmeProvider := Provider{
certificateStore: &traefiktls.CertificateStore{
DynamicCerts: test.dynamicCerts,
StaticCerts: test.staticCerts,
},
certificates: test.acmeCertificates,
resolvingDomains: test.resolvingDomains,
}
domains := acmeProvider.getUncheckedDomains(test.domains, false)
assert.Equal(t, len(test.expectedDomains), len(domains), "Unexpected domains.")
})
}
}
func TestGetValidDomain(t *testing.T) {
testCases := []struct {
desc string
domains types.Domain
wildcardAllowed bool
dnsChallenge *DNSChallenge
expectedErr string
expectedDomains []string
}{
{
desc: "valid wildcard",
domains: types.Domain{Main: "*.traefik.wtf"},
dnsChallenge: &DNSChallenge{},
wildcardAllowed: true,
expectedErr: "",
expectedDomains: []string{"*.traefik.wtf"},
},
{
desc: "no wildcard",
domains: types.Domain{Main: "traefik.wtf", SANs: []string{"foo.traefik.wtf"}},
dnsChallenge: &DNSChallenge{},
expectedErr: "",
wildcardAllowed: true,
expectedDomains: []string{"traefik.wtf", "foo.traefik.wtf"},
},
{
desc: "unauthorized wildcard",
domains: types.Domain{Main: "*.traefik.wtf"},
dnsChallenge: &DNSChallenge{},
wildcardAllowed: false,
expectedErr: "unable to generate a wildcard certificate in ACME provider for domain \"*.traefik.wtf\" from a 'Host' rule",
expectedDomains: nil,
},
{
desc: "no domain",
domains: types.Domain{},
dnsChallenge: nil,
wildcardAllowed: true,
expectedErr: "unable to generate a certificate in ACME provider when no domain is given",
expectedDomains: nil,
},
{
desc: "no DNSChallenge",
domains: types.Domain{Main: "*.traefik.wtf", SANs: []string{"foo.traefik.wtf"}},
dnsChallenge: nil,
wildcardAllowed: true,
expectedErr: "unable to generate a wildcard certificate in ACME provider for domain \"*.traefik.wtf,foo.traefik.wtf\" : ACME needs a DNSChallenge",
expectedDomains: nil,
},
{
desc: "unauthorized wildcard with SAN",
domains: types.Domain{Main: "*.*.traefik.wtf", SANs: []string{"foo.traefik.wtf"}},
dnsChallenge: &DNSChallenge{},
wildcardAllowed: true,
expectedErr: "unable to generate a wildcard certificate in ACME provider for domain \"*.*.traefik.wtf,foo.traefik.wtf\" : ACME does not allow '*.*' wildcard domain",
expectedDomains: nil,
},
{
desc: "wildcard and SANs",
domains: types.Domain{Main: "*.traefik.wtf", SANs: []string{"traefik.wtf"}},
dnsChallenge: &DNSChallenge{},
wildcardAllowed: true,
expectedErr: "",
expectedDomains: []string{"*.traefik.wtf", "traefik.wtf"},
},
{
desc: "unexpected SANs",
domains: types.Domain{Main: "*.traefik.wtf", SANs: []string{"*.acme.wtf"}},
dnsChallenge: &DNSChallenge{},
wildcardAllowed: true,
expectedErr: "unable to generate a certificate in ACME provider for domains \"*.traefik.wtf,*.acme.wtf\": SAN \"*.acme.wtf\" can not be a wildcard domain",
expectedDomains: nil,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
acmeProvider := Provider{Configuration: &Configuration{DNSChallenge: test.dnsChallenge}}
domains, err := acmeProvider.getValidDomains(test.domains, test.wildcardAllowed)
if len(test.expectedErr) > 0 {
assert.EqualError(t, err, test.expectedErr, "Unexpected error.")
} else {
assert.Equal(t, len(test.expectedDomains), len(domains), "Unexpected domains.")
}
})
}
}
func TestDeleteUnnecessaryDomains(t *testing.T) {
testCases := []struct {
desc string
domains []types.Domain
expectedDomains []types.Domain
}{
{
desc: "no domain to delete",
domains: []types.Domain{
{
Main: "acme.wtf",
SANs: []string{"traefik.acme.wtf", "foo.bar"},
},
{
Main: "*.foo.acme.wtf",
},
{
Main: "acme02.wtf",
SANs: []string{"traefik.acme02.wtf", "bar.foo"},
},
},
expectedDomains: []types.Domain{
{
Main: "acme.wtf",
SANs: []string{"traefik.acme.wtf", "foo.bar"},
},
{
Main: "*.foo.acme.wtf",
SANs: []string{},
},
{
Main: "acme02.wtf",
SANs: []string{"traefik.acme02.wtf", "bar.foo"},
},
},
},
{
desc: "wildcard and root domain",
domains: []types.Domain{
{
Main: "acme.wtf",
},
{
Main: "*.acme.wtf",
SANs: []string{"acme.wtf"},
},
},
expectedDomains: []types.Domain{
{
Main: "acme.wtf",
SANs: []string{},
},
{
Main: "*.acme.wtf",
SANs: []string{},
},
},
},
{
desc: "2 equals domains",
domains: []types.Domain{
{
Main: "acme.wtf",
SANs: []string{"traefik.acme.wtf", "foo.bar"},
},
{
Main: "acme.wtf",
SANs: []string{"traefik.acme.wtf", "foo.bar"},
},
},
expectedDomains: []types.Domain{
{
Main: "acme.wtf",
SANs: []string{"traefik.acme.wtf", "foo.bar"},
},
},
},
{
desc: "2 domains with same values",
domains: []types.Domain{
{
Main: "acme.wtf",
SANs: []string{"traefik.acme.wtf"},
},
{
Main: "acme.wtf",
SANs: []string{"traefik.acme.wtf", "foo.bar"},
},
},
expectedDomains: []types.Domain{
{
Main: "acme.wtf",
SANs: []string{"traefik.acme.wtf"},
},
{
Main: "foo.bar",
SANs: []string{},
},
},
},
{
desc: "domain totally checked by wildcard",
domains: []types.Domain{
{
Main: "who.acme.wtf",
SANs: []string{"traefik.acme.wtf", "bar.acme.wtf"},
},
{
Main: "*.acme.wtf",
},
},
expectedDomains: []types.Domain{
{
Main: "*.acme.wtf",
SANs: []string{},
},
},
},
{
desc: "duplicated wildcard",
domains: []types.Domain{
{
Main: "*.acme.wtf",
SANs: []string{"acme.wtf"},
},
{
Main: "*.acme.wtf",
},
},
expectedDomains: []types.Domain{
{
Main: "*.acme.wtf",
SANs: []string{"acme.wtf"},
},
},
},
{
desc: "domain partially checked by wildcard",
domains: []types.Domain{
{
Main: "traefik.acme.wtf",
SANs: []string{"acme.wtf", "foo.bar"},
},
{
Main: "*.acme.wtf",
},
{
Main: "who.acme.wtf",
SANs: []string{"traefik.acme.wtf", "bar.acme.wtf"},
},
},
expectedDomains: []types.Domain{
{
Main: "acme.wtf",
SANs: []string{"foo.bar"},
},
{
Main: "*.acme.wtf",
SANs: []string{},
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
acmeProvider := Provider{Configuration: &Configuration{Domains: test.domains}}
acmeProvider.deleteUnnecessaryDomains()
assert.Equal(t, test.expectedDomains, acmeProvider.Domains, "unexpected domain")
})
}
}
func TestIsAccountMatchingCaServer(t *testing.T) {
testCases := []struct {
desc string
accountURI string
serverURI string
expected bool
}{
{
desc: "acme staging with matching account",
accountURI: "https://acme-staging-v02.api.letsencrypt.org/acme/acct/1234567",
serverURI: "https://acme-staging-v02.api.letsencrypt.org/acme/directory",
expected: true,
},
{
desc: "acme production with matching account",
accountURI: "https://acme-v02.api.letsencrypt.org/acme/acct/1234567",
serverURI: "https://acme-v02.api.letsencrypt.org/acme/directory",
expected: true,
},
{
desc: "http only acme with matching account",
accountURI: "http://acme.api.letsencrypt.org/acme/acct/1234567",
serverURI: "http://acme.api.letsencrypt.org/acme/directory",
expected: true,
},
{
desc: "different subdomains for account and server",
accountURI: "https://test1.example.org/acme/acct/1234567",
serverURI: "https://test2.example.org/acme/directory",
expected: false,
},
{
desc: "different domains for account and server",
accountURI: "https://test.example1.org/acme/acct/1234567",
serverURI: "https://test.example2.org/acme/directory",
expected: false,
},
{
desc: "different tld for account and server",
accountURI: "https://test.example.com/acme/acct/1234567",
serverURI: "https://test.example.org/acme/directory",
expected: false,
},
{
desc: "malformed account url",
accountURI: "//|\\/test.example.com/acme/acct/1234567",
serverURI: "https://test.example.com/acme/directory",
expected: false,
},
{
desc: "malformed server url",
accountURI: "https://test.example.com/acme/acct/1234567",
serverURI: "//|\\/test.example.com/acme/directory",
expected: false,
},
{
desc: "malformed server and account url",
accountURI: "//|\\/test.example.com/acme/acct/1234567",
serverURI: "//|\\/test.example.com/acme/directory",
expected: false,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
result := isAccountMatchingCaServer(test.accountURI, test.serverURI)
assert.Equal(t, test.expected, result)
})
}
}
func TestUseBackOffToObtainCertificate(t *testing.T) {
testCases := []struct {
desc string
domains []string
dnsChallenge *DNSChallenge
expectedResponse bool
}{
{
desc: "only one single domain",
domains: []string{"acme.wtf"},
dnsChallenge: &DNSChallenge{},
expectedResponse: false,
},
{
desc: "only one wildcard domain",
domains: []string{"*.acme.wtf"},
dnsChallenge: &DNSChallenge{},
expectedResponse: false,
},
{
desc: "wildcard domain with no root domain",
domains: []string{"*.acme.wtf", "foo.acme.wtf", "bar.acme.wtf", "foo.bar"},
dnsChallenge: &DNSChallenge{},
expectedResponse: false,
},
{
desc: "wildcard and root domain",
domains: []string{"*.acme.wtf", "foo.acme.wtf", "bar.acme.wtf", "acme.wtf"},
dnsChallenge: &DNSChallenge{},
expectedResponse: true,
},
{
desc: "wildcard and root domain but no DNS challenge",
domains: []string{"*.acme.wtf", "acme.wtf"},
dnsChallenge: nil,
expectedResponse: false,
},
{
desc: "two wildcard domains (must never happen)",
domains: []string{"*.acme.wtf", "*.bar.foo"},
dnsChallenge: nil,
expectedResponse: false,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
acmeProvider := Provider{Configuration: &Configuration{DNSChallenge: test.dnsChallenge}}
actualResponse := acmeProvider.useCertificateWithRetry(test.domains)
assert.Equal(t, test.expectedResponse, actualResponse, "unexpected response to use backOff")
})
}
}
func TestInitAccount(t *testing.T) {
testCases := []struct {
desc string
account *Account
email string
keyType string
expectedAccount *Account
}{
{
desc: "Existing account with all information",
account: &Account{
Email: "foo@foo.net",
KeyType: acme.EC256,
},
expectedAccount: &Account{
Email: "foo@foo.net",
KeyType: acme.EC256,
},
},
{
desc: "Account nil",
email: "foo@foo.net",
keyType: "EC256",
expectedAccount: &Account{
Email: "foo@foo.net",
KeyType: acme.EC256,
},
},
{
desc: "Existing account with no email",
account: &Account{
KeyType: acme.RSA4096,
},
email: "foo@foo.net",
keyType: "EC256",
expectedAccount: &Account{
Email: "foo@foo.net",
KeyType: acme.EC256,
},
},
{
desc: "Existing account with no key type",
account: &Account{
Email: "foo@foo.net",
},
email: "bar@foo.net",
keyType: "EC256",
expectedAccount: &Account{
Email: "foo@foo.net",
KeyType: acme.EC256,
},
},
{
desc: "Existing account and provider with no key type",
account: &Account{
Email: "foo@foo.net",
},
email: "bar@foo.net",
expectedAccount: &Account{
Email: "foo@foo.net",
KeyType: acme.RSA4096,
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
acmeProvider := Provider{account: test.account, Configuration: &Configuration{Email: test.email, KeyType: test.keyType}}
actualAccount, err := acmeProvider.initAccount()
assert.Nil(t, err, "Init account in error")
assert.Equal(t, test.expectedAccount.Email, actualAccount.Email, "unexpected email account")
assert.Equal(t, test.expectedAccount.KeyType, actualAccount.KeyType, "unexpected keyType account")
})
}
}

244
old/tls/certificate.go Normal file
View file

@ -0,0 +1,244 @@
package tls
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
"sort"
"strings"
"github.com/containous/traefik/log"
"github.com/containous/traefik/tls/generate"
)
var (
// MinVersion Map of allowed TLS minimum versions
MinVersion = map[string]uint16{
`VersionTLS10`: tls.VersionTLS10,
`VersionTLS11`: tls.VersionTLS11,
`VersionTLS12`: tls.VersionTLS12,
}
// CipherSuites Map of TLS CipherSuites from crypto/tls
// Available CipherSuites defined at https://golang.org/pkg/crypto/tls/#pkg-constants
CipherSuites = map[string]uint16{
`TLS_RSA_WITH_RC4_128_SHA`: tls.TLS_RSA_WITH_RC4_128_SHA,
`TLS_RSA_WITH_3DES_EDE_CBC_SHA`: tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
`TLS_RSA_WITH_AES_128_CBC_SHA`: tls.TLS_RSA_WITH_AES_128_CBC_SHA,
`TLS_RSA_WITH_AES_256_CBC_SHA`: tls.TLS_RSA_WITH_AES_256_CBC_SHA,
`TLS_RSA_WITH_AES_128_CBC_SHA256`: tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
`TLS_RSA_WITH_AES_128_GCM_SHA256`: tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
`TLS_RSA_WITH_AES_256_GCM_SHA384`: tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
`TLS_ECDHE_ECDSA_WITH_RC4_128_SHA`: tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
`TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA`: tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
`TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA`: tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
`TLS_ECDHE_RSA_WITH_RC4_128_SHA`: tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
`TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA`: tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
`TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA`: tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
`TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA`: tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
`TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256`: tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
`TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256`: tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
`TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`: tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
`TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`: tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
`TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384`: tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
`TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`: tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
`TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305`: tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
`TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305`: tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
}
)
// Certificate holds a SSL cert/key pair
// Certs and Key could be either a file path, or the file content itself
type Certificate struct {
CertFile FileOrContent
KeyFile FileOrContent
}
// Certificates defines traefik certificates type
// Certs and Keys could be either a file path, or the file content itself
type Certificates []Certificate
// FileOrContent hold a file path or content
type FileOrContent string
func (f FileOrContent) String() string {
return string(f)
}
// IsPath returns true if the FileOrContent is a file path, otherwise returns false
func (f FileOrContent) IsPath() bool {
_, err := os.Stat(f.String())
return err == nil
}
func (f FileOrContent) Read() ([]byte, error) {
var content []byte
if _, err := os.Stat(f.String()); err == nil {
content, err = ioutil.ReadFile(f.String())
if err != nil {
return nil, err
}
} else {
content = []byte(f)
}
return content, nil
}
// CreateTLSConfig creates a TLS config from Certificate structures
func (c *Certificates) CreateTLSConfig(entryPointName string) (*tls.Config, error) {
config := &tls.Config{}
domainsCertificates := make(map[string]map[string]*tls.Certificate)
if c.isEmpty() {
config.Certificates = []tls.Certificate{}
cert, err := generate.DefaultCertificate()
if err != nil {
return nil, err
}
config.Certificates = append(config.Certificates, *cert)
} else {
for _, certificate := range *c {
err := certificate.AppendCertificates(domainsCertificates, entryPointName)
if err != nil {
log.Errorf("Unable to add a certificate to the entryPoint %q : %v", entryPointName, err)
continue
}
for _, certDom := range domainsCertificates {
for _, cert := range certDom {
config.Certificates = append(config.Certificates, *cert)
}
}
}
}
return config, nil
}
// isEmpty checks if the certificates list is empty
func (c *Certificates) isEmpty() bool {
if len(*c) == 0 {
return true
}
var key int
for _, cert := range *c {
if len(cert.CertFile.String()) != 0 && len(cert.KeyFile.String()) != 0 {
break
}
key++
}
return key == len(*c)
}
// AppendCertificates appends a Certificate to a certificates map sorted by entrypoints
func (c *Certificate) AppendCertificates(certs map[string]map[string]*tls.Certificate, ep string) error {
certContent, err := c.CertFile.Read()
if err != nil {
return fmt.Errorf("unable to read CertFile : %v", err)
}
keyContent, err := c.KeyFile.Read()
if err != nil {
return fmt.Errorf("unable to read KeyFile : %v", err)
}
tlsCert, err := tls.X509KeyPair(certContent, keyContent)
if err != nil {
return fmt.Errorf("unable to generate TLS certificate : %v", err)
}
parsedCert, _ := x509.ParseCertificate(tlsCert.Certificate[0])
var SANs []string
if parsedCert.Subject.CommonName != "" {
SANs = append(SANs, parsedCert.Subject.CommonName)
}
if parsedCert.DNSNames != nil {
sort.Strings(parsedCert.DNSNames)
for _, dnsName := range parsedCert.DNSNames {
if dnsName != parsedCert.Subject.CommonName {
SANs = append(SANs, dnsName)
}
}
}
if parsedCert.IPAddresses != nil {
for _, ip := range parsedCert.IPAddresses {
if ip.String() != parsedCert.Subject.CommonName {
SANs = append(SANs, ip.String())
}
}
}
certKey := strings.Join(SANs, ",")
certExists := false
if certs[ep] == nil {
certs[ep] = make(map[string]*tls.Certificate)
} else {
for domains := range certs[ep] {
if domains == certKey {
certExists = true
break
}
}
}
if certExists {
log.Warnf("Into EntryPoint %s, try to add certificate for domains which already have this certificate (%s). The new certificate will not be append to the EntryPoint.", ep, certKey)
} else {
log.Debugf("Add certificate for domains %s", certKey)
certs[ep][certKey] = &tlsCert
}
return err
}
func (c *Certificate) getTruncatedCertificateName() string {
certName := c.CertFile.String()
// Truncate certificate information only if it's a well formed certificate content with more than 50 characters
if !c.CertFile.IsPath() && strings.HasPrefix(certName, certificateHeader) && len(certName) > len(certificateHeader)+50 {
certName = strings.TrimPrefix(c.CertFile.String(), certificateHeader)[:50]
}
return certName
}
// 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 (c *Certificates) String() string {
if len(*c) == 0 {
return ""
}
var result []string
for _, certificate := range *c {
result = append(result, certificate.CertFile.String()+","+certificate.KeyFile.String())
}
return strings.Join(result, ";")
}
// 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 (c *Certificates) Set(value string) error {
certificates := strings.Split(value, ";")
for _, certificate := range certificates {
files := strings.Split(certificate, ",")
if len(files) != 2 {
return fmt.Errorf("bad certificates format: %s", value)
}
*c = append(*c, Certificate{
CertFile: FileOrContent(files[0]),
KeyFile: FileOrContent(files[1]),
})
}
return nil
}
// Type is type of the struct
func (c *Certificates) Type() string {
return "certificates"
}

View file

@ -0,0 +1,137 @@
package tls
import (
"crypto/tls"
"net"
"sort"
"strings"
"time"
"github.com/containous/traefik/log"
"github.com/containous/traefik/safe"
"github.com/patrickmn/go-cache"
)
// CertificateStore store for dynamic and static certificates
type CertificateStore struct {
DynamicCerts *safe.Safe
StaticCerts *safe.Safe
DefaultCertificate *tls.Certificate
CertCache *cache.Cache
SniStrict bool
}
// NewCertificateStore create a store for dynamic and static certificates
func NewCertificateStore() *CertificateStore {
return &CertificateStore{
StaticCerts: &safe.Safe{},
DynamicCerts: &safe.Safe{},
CertCache: cache.New(1*time.Hour, 10*time.Minute),
}
}
// GetAllDomains return a slice with all the certificate domain
func (c CertificateStore) GetAllDomains() []string {
var allCerts []string
// Get static certificates
if c.StaticCerts != nil && c.StaticCerts.Get() != nil {
for domains := range c.StaticCerts.Get().(map[string]*tls.Certificate) {
allCerts = append(allCerts, domains)
}
}
// Get dynamic certificates
if c.DynamicCerts != nil && c.DynamicCerts.Get() != nil {
for domains := range c.DynamicCerts.Get().(map[string]*tls.Certificate) {
allCerts = append(allCerts, domains)
}
}
return allCerts
}
// GetBestCertificate returns the best match certificate, and caches the response
func (c CertificateStore) GetBestCertificate(clientHello *tls.ClientHelloInfo) *tls.Certificate {
domainToCheck := strings.ToLower(strings.TrimSpace(clientHello.ServerName))
if len(domainToCheck) == 0 {
// If no ServerName is provided, Check for local IP address matches
host, _, err := net.SplitHostPort(clientHello.Conn.LocalAddr().String())
if err != nil {
log.Debugf("Could not split host/port: %v", err)
}
domainToCheck = strings.TrimSpace(host)
}
if cert, ok := c.CertCache.Get(domainToCheck); ok {
return cert.(*tls.Certificate)
}
matchedCerts := map[string]*tls.Certificate{}
if c.DynamicCerts != nil && c.DynamicCerts.Get() != nil {
for domains, cert := range c.DynamicCerts.Get().(map[string]*tls.Certificate) {
for _, certDomain := range strings.Split(domains, ",") {
if MatchDomain(domainToCheck, certDomain) {
matchedCerts[certDomain] = cert
}
}
}
}
if c.StaticCerts != nil && c.StaticCerts.Get() != nil {
for domains, cert := range c.StaticCerts.Get().(map[string]*tls.Certificate) {
for _, certDomain := range strings.Split(domains, ",") {
if MatchDomain(domainToCheck, certDomain) {
matchedCerts[certDomain] = cert
}
}
}
}
if len(matchedCerts) > 0 {
// sort map by keys
keys := make([]string, 0, len(matchedCerts))
for k := range matchedCerts {
keys = append(keys, k)
}
sort.Strings(keys)
// cache best match
c.CertCache.SetDefault(domainToCheck, matchedCerts[keys[len(keys)-1]])
return matchedCerts[keys[len(keys)-1]]
}
return nil
}
// ContainsCertificates checks if there are any certs in the store
func (c CertificateStore) ContainsCertificates() bool {
return c.StaticCerts.Get() != nil || c.DynamicCerts.Get() != nil
}
// ResetCache clears the cache in the store
func (c CertificateStore) ResetCache() {
if c.CertCache != nil {
c.CertCache.Flush()
}
}
// MatchDomain return true if a domain match the cert domain
func MatchDomain(domain string, certDomain string) bool {
if domain == certDomain {
return true
}
for len(certDomain) > 0 && certDomain[len(certDomain)-1] == '.' {
certDomain = certDomain[:len(certDomain)-1]
}
labels := strings.Split(domain, ".")
for i := range labels {
labels[i] = "*"
candidate := strings.Join(labels, ".")
if certDomain == candidate {
return true
}
}
return false
}

View file

@ -0,0 +1,94 @@
package generate
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/hex"
"encoding/pem"
"fmt"
"math/big"
"time"
)
// DefaultDomain Traefik domain for the default certificate
const DefaultDomain = "TRAEFIK DEFAULT CERT"
// DefaultCertificate generates random TLS certificates
func DefaultCertificate() (*tls.Certificate, error) {
randomBytes := make([]byte, 100)
_, err := rand.Read(randomBytes)
if err != nil {
return nil, err
}
zBytes := sha256.Sum256(randomBytes)
z := hex.EncodeToString(zBytes[:sha256.Size])
domain := fmt.Sprintf("%s.%s.traefik.default", z[:32], z[32:])
certPEM, keyPEM, err := KeyPair(domain, time.Time{})
if err != nil {
return nil, err
}
certificate, err := tls.X509KeyPair(certPEM, keyPEM)
if err != nil {
return nil, err
}
return &certificate, nil
}
// KeyPair generates cert and key files
func KeyPair(domain string, expiration time.Time) ([]byte, []byte, error) {
rsaPrivKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rsaPrivKey)})
certPEM, err := PemCert(rsaPrivKey, domain, expiration)
if err != nil {
return nil, nil, err
}
return certPEM, keyPEM, nil
}
// PemCert generates PEM cert file
func PemCert(privKey *rsa.PrivateKey, domain string, expiration time.Time) ([]byte, error) {
derBytes, err := derCert(privKey, expiration, domain)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}), nil
}
func derCert(privKey *rsa.PrivateKey, expiration time.Time, domain string) ([]byte, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, err
}
if expiration.IsZero() {
expiration = time.Now().Add(365 * (24 * time.Hour))
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: DefaultDomain,
},
NotBefore: time.Now(),
NotAfter: expiration,
KeyUsage: x509.KeyUsageKeyEncipherment,
BasicConstraintsValid: true,
DNSNames: []string{domain},
}
return x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
}

101
old/tls/tls.go Normal file
View file

@ -0,0 +1,101 @@
package tls
import (
"crypto/tls"
"fmt"
"strings"
"github.com/containous/traefik/log"
"github.com/sirupsen/logrus"
)
const (
certificateHeader = "-----BEGIN CERTIFICATE-----\n"
)
// ClientCA defines traefik CA files for a entryPoint
// and it indicates if they are mandatory or have just to be analyzed if provided
type ClientCA struct {
Files FilesOrContents
Optional bool
}
// TLS configures TLS for an entry point
type TLS struct {
MinVersion string `export:"true"`
CipherSuites []string
Certificates Certificates
ClientCA ClientCA
DefaultCertificate *Certificate
SniStrict bool `export:"true"`
}
// FilesOrContents hold the CA we want to have in root
type FilesOrContents []FileOrContent
// Configuration allows mapping a TLS certificate to a list of entrypoints
type Configuration struct {
EntryPoints []string
Certificate *Certificate
}
// 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 (r *FilesOrContents) String() string {
sliceOfString := make([]string, len([]FileOrContent(*r)))
for key, value := range *r {
sliceOfString[key] = value.String()
}
return strings.Join(sliceOfString, ",")
}
// 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 (r *FilesOrContents) Set(value string) error {
filesOrContents := strings.Split(value, ",")
if len(filesOrContents) == 0 {
return fmt.Errorf("bad FilesOrContents format: %s", value)
}
for _, fileOrContent := range filesOrContents {
*r = append(*r, FileOrContent(fileOrContent))
}
return nil
}
// Get return the FilesOrContents list
func (r *FilesOrContents) Get() interface{} {
return *r
}
// SetValue sets the FilesOrContents with val
func (r *FilesOrContents) SetValue(val interface{}) {
*r = val.(FilesOrContents)
}
// Type is type of the struct
func (r *FilesOrContents) Type() string {
return "filesorcontents"
}
// SortTLSPerEntryPoints converts TLS configuration sorted by Certificates into TLS configuration sorted by EntryPoints
func SortTLSPerEntryPoints(configurations []*Configuration, epConfiguration map[string]map[string]*tls.Certificate, defaultEntryPoints []string) {
if epConfiguration == nil {
epConfiguration = make(map[string]map[string]*tls.Certificate)
}
for _, conf := range configurations {
if conf.EntryPoints == nil || len(conf.EntryPoints) == 0 {
if log.GetLevel() >= logrus.DebugLevel {
log.Debugf("No entryPoint is defined to add the certificate %s, it will be added to the default entryPoints: %s",
conf.Certificate.getTruncatedCertificateName(),
strings.Join(defaultEntryPoints, ", "))
}
conf.EntryPoints = append(conf.EntryPoints, defaultEntryPoints...)
}
for _, ep := range conf.EntryPoints {
if err := conf.Certificate.AppendCertificates(epConfiguration, ep); err != nil {
log.Errorf("Unable to append certificate %s to entrypoint %s: %v", conf.Certificate.getTruncatedCertificateName(), ep, err)
}
}
}
}

View file

@ -124,7 +124,7 @@ func (p *Provider) ListenRequest(domain string) (*tls.Certificate, error) {
} }
// Init for compatibility reason the BaseProvider implements an empty Init // Init for compatibility reason the BaseProvider implements an empty Init
func (p *Provider) Init(_ types.Constraints) error { func (p *Provider) Init() error {
ctx := log.With(context.Background(), log.Str(log.ProviderName, "acme")) ctx := log.With(context.Background(), log.Str(log.ProviderName, "acme"))
logger := log.FromContext(ctx) logger := log.FromContext(ctx)

View file

@ -25,10 +25,10 @@ func TestGetUncheckedCertificates(t *testing.T) {
domainSafe := &safe.Safe{} domainSafe := &safe.Safe{}
domainSafe.Set(domainMap) domainSafe.Set(domainMap)
// FIXME Add a test for DefaultCertificate
testCases := []struct { testCases := []struct {
desc string desc string
dynamicCerts *safe.Safe dynamicCerts *safe.Safe
staticCerts *safe.Safe
resolvingDomains map[string]struct{} resolvingDomains map[string]struct{}
acmeCertificates []*Certificate acmeCertificates []*Certificate
domains []string domains []string
@ -45,12 +45,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
dynamicCerts: wildcardSafe, dynamicCerts: wildcardSafe,
expectedDomains: nil, expectedDomains: nil,
}, },
{
desc: "wildcard already exists in static certificates",
domains: []string{"*.traefik.wtf"},
staticCerts: wildcardSafe,
expectedDomains: nil,
},
{ {
desc: "wildcard already exists in ACME certificates", desc: "wildcard already exists in ACME certificates",
domains: []string{"*.traefik.wtf"}, domains: []string{"*.traefik.wtf"},
@ -72,12 +66,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
dynamicCerts: domainSafe, dynamicCerts: domainSafe,
expectedDomains: []string{"foo.traefik.wtf"}, expectedDomains: []string{"foo.traefik.wtf"},
}, },
{
desc: "domain CN already exists in static certificates and SANs to generate",
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
staticCerts: domainSafe,
expectedDomains: []string{"foo.traefik.wtf"},
},
{ {
desc: "domain CN already exists in ACME certificates and SANs to generate", desc: "domain CN already exists in ACME certificates and SANs to generate",
domains: []string{"traefik.wtf", "foo.traefik.wtf"}, domains: []string{"traefik.wtf", "foo.traefik.wtf"},
@ -94,12 +82,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
dynamicCerts: domainSafe, dynamicCerts: domainSafe,
expectedDomains: nil, expectedDomains: nil,
}, },
{
desc: "domain already exists in static certificates",
domains: []string{"traefik.wtf"},
staticCerts: domainSafe,
expectedDomains: nil,
},
{ {
desc: "domain already exists in ACME certificates", desc: "domain already exists in ACME certificates",
domains: []string{"traefik.wtf"}, domains: []string{"traefik.wtf"},
@ -116,12 +98,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
dynamicCerts: wildcardSafe, dynamicCerts: wildcardSafe,
expectedDomains: nil, expectedDomains: nil,
}, },
{
desc: "domain matched by wildcard in static certificates",
domains: []string{"who.traefik.wtf", "foo.traefik.wtf"},
staticCerts: wildcardSafe,
expectedDomains: nil,
},
{ {
desc: "domain matched by wildcard in ACME certificates", desc: "domain matched by wildcard in ACME certificates",
domains: []string{"who.traefik.wtf", "foo.traefik.wtf"}, domains: []string{"who.traefik.wtf", "foo.traefik.wtf"},
@ -190,7 +166,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
acmeProvider := Provider{ acmeProvider := Provider{
certificateStore: &traefiktls.CertificateStore{ certificateStore: &traefiktls.CertificateStore{
DynamicCerts: test.dynamicCerts, DynamicCerts: test.dynamicCerts,
StaticCerts: test.staticCerts,
}, },
certificates: test.acmeCertificates, certificates: test.acmeCertificates,
resolvingDomains: test.resolvingDomains, resolvingDomains: test.resolvingDomains,

View file

@ -8,20 +8,16 @@ import (
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
"github.com/containous/traefik/provider" "github.com/containous/traefik/provider"
"github.com/containous/traefik/safe" "github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
) )
// ProviderAggregator aggregates providers. // ProviderAggregator aggregates providers.
type ProviderAggregator struct { type ProviderAggregator struct {
providers []provider.Provider providers []provider.Provider
constraints types.Constraints
} }
// NewProviderAggregator returns an aggregate of all the providers configured in the static configuration. // NewProviderAggregator returns an aggregate of all the providers configured in the static configuration.
func NewProviderAggregator(conf static.Configuration) ProviderAggregator { func NewProviderAggregator(conf static.Providers) ProviderAggregator {
p := ProviderAggregator{ p := ProviderAggregator{}
constraints: conf.Constraints,
}
if conf.File != nil { if conf.File != nil {
p.quietAddProvider(conf.File) p.quietAddProvider(conf.File)
@ -39,7 +35,7 @@ func (p *ProviderAggregator) quietAddProvider(provider provider.Provider) {
// AddProvider adds a provider in the providers map. // AddProvider adds a provider in the providers map.
func (p *ProviderAggregator) AddProvider(provider provider.Provider) error { func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
err := provider.Init(p.constraints) err := provider.Init()
if err != nil { if err != nil {
return err return err
} }
@ -48,7 +44,7 @@ func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
} }
// Init the provider // Init the provider
func (p ProviderAggregator) Init(_ types.Constraints) error { func (p ProviderAggregator) Init() error {
return nil return nil
} }

View file

@ -25,8 +25,7 @@ type BaseProvider struct {
} }
// Init for compatibility reason the BaseProvider implements an empty Init. // Init for compatibility reason the BaseProvider implements an empty Init.
func (p *BaseProvider) Init(constraints types.Constraints) error { func (p *BaseProvider) Init() error {
p.Constraints = append(p.Constraints, constraints...)
return nil return nil
} }

View file

@ -15,7 +15,6 @@ import (
"github.com/containous/traefik/provider" "github.com/containous/traefik/provider"
"github.com/containous/traefik/safe" "github.com/containous/traefik/safe"
"github.com/containous/traefik/tls" "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/pkg/errors" "github.com/pkg/errors"
"gopkg.in/fsnotify.v1" "gopkg.in/fsnotify.v1"
) )
@ -32,8 +31,8 @@ type Provider struct {
} }
// Init the provider // Init the provider
func (p *Provider) Init(constraints types.Constraints) error { func (p *Provider) Init() error {
return p.BaseProvider.Init(constraints) return p.BaseProvider.Init()
} }
// Provide allows the file provider to provide configurations to traefik // Provide allows the file provider to provide configurations to traefik

View file

@ -3,7 +3,6 @@ package provider
import ( import (
"github.com/containous/traefik/config" "github.com/containous/traefik/config"
"github.com/containous/traefik/safe" "github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
) )
// Provider defines methods of a provider. // Provider defines methods of a provider.
@ -11,5 +10,5 @@ type Provider interface {
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
Provide(configurationChan chan<- config.Message, pool *safe.Pool) error Provide(configurationChan chan<- config.Message, pool *safe.Pool) error
Init(constraints types.Constraints) error Init() error
} }

Some files were not shown because too many files have changed in this diff Show more