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
import (
"context"
"crypto"
"crypto/rand"
"crypto/rsa"
@ -15,8 +16,8 @@ import (
"time"
"github.com/containous/traefik/log"
acmeprovider "github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/types"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/types"
"github.com/xenolf/lego/acme"
)
@ -72,7 +73,7 @@ func (a *Account) Init() error {
// NewAccount creates an account
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
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)

View file

@ -22,9 +22,9 @@ import (
"github.com/containous/staert"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/log"
acmeprovider "github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/types"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/eapache/channels"
"github.com/xenolf/lego/acme"
@ -208,7 +208,7 @@ func (a *ACME) leadershipListener(elected bool) error {
needRegister = true
} else if len(account.KeyType) == 0 {
// 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)

View file

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

View file

@ -6,7 +6,7 @@ import (
"os"
"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

View file

@ -8,163 +8,77 @@ import (
"github.com/containous/flaeg/parse"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/old/api"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/middlewares"
"github.com/containous/traefik/old/provider"
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"
"github.com/containous/traefik/config/static"
"github.com/containous/traefik/provider"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/provider/file"
traefiktls "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/elazarl/go-bindata-assetfs"
"github.com/thoas/stats"
)
func TestDo_globalConfiguration(t *testing.T) {
config := &configuration.GlobalConfiguration{}
config := &static.Configuration{}
config.Debug = true
config.CheckNewVersion = true
config.Global = &static.Global{
Debug: true,
CheckNewVersion: true,
SendAnonymousUsage: true,
}
config.AccessLog = &types.AccessLog{
FilePath: "AccessLog FilePath",
Format: "AccessLog Format",
}
config.LogLevel = "LogLevel"
config.EntryPoints = configuration.EntryPoints{
config.Log = &types.TraefikLog{
LogLevel: "LogLevel",
FilePath: "/foo/path",
Format: "json",
}
config.EntryPoints = static.EntryPoints{
"foo": {
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{
MinVersion: "foo MinVersion",
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{
Files: traefiktls.FilesOrContents{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"},
Optional: false,
},
},
Redirect: &types.Redirect{
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{
ProxyProtocol: &static.ProxyProtocol{
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
},
},
"fii": {
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{
MinVersion: "fii MinVersion",
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{
Files: traefiktls.FilesOrContents{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"},
Optional: false,
},
},
Redirect: &types.Redirect{
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{
ProxyProtocol: &static.ProxyProtocol{
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{
Email: "acme Email",
Domains: []types.Domain{
@ -186,33 +100,26 @@ func TestDo_globalConfiguration(t *testing.T) {
// ...
},
}
config.DefaultEntryPoints = configuration.DefaultEntryPoints{"DefaultEntryPoints 1", "DefaultEntryPoints 2", "DefaultEntryPoints 3"}
config.ProvidersThrottleDuration = parse.Duration(666 * 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.Providers = &static.Providers{
ProvidersThrottleDuration: parse.Duration(111 * time.Second),
}
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",
Dashboard: true,
Debug: true,
CurrentConfigurations: &safe.Safe{},
config.API = &static.API{
EntryPoint: "traefik",
Dashboard: true,
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{
Asset: func(path string) ([]byte, error) {
return nil, nil
@ -225,48 +132,10 @@ func TestDo_globalConfiguration(t *testing.T) {
},
Prefix: "fii",
},
Middlewares: []string{"first", "second"},
}
config.RespondingTimeouts = &configuration.RespondingTimeouts{
ReadTimeout: parse.Duration(666 * time.Second),
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{
config.Providers.File = &file.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "file Filename",
@ -287,368 +156,8 @@ func TestDo_globalConfiguration(t *testing.T) {
},
Directory: "file Directory",
}
config.Marathon = &marathon.Provider{
BaseProvider: provider.BaseProvider{
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",
},
}
// FIXME Test the other providers once they are migrated
cleanJSON, err := Do(config, true)
if err != nil {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,6 +10,7 @@ import (
"time"
"github.com/containous/traefik/anonymize"
"github.com/containous/traefik/config/static"
"github.com/containous/traefik/log"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/version"
@ -29,15 +30,15 @@ type data struct {
}
// Collect anonymous data.
func Collect(globalConfiguration *configuration.GlobalConfiguration) error {
anonConfig, err := anonymize.Do(globalConfiguration, false)
func Collect(staticConfiguration *static.Configuration) error {
anonConfig, err := anonymize.Do(staticConfiguration, false)
if err != nil {
return err
}
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 {
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 (
"testing"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/tls"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -186,277 +185,70 @@ func TestEntryPoints_Set(t *testing.T) {
name: "all parameters camelcase",
expression: "Name:foo " +
"Address::8000 " +
"TLS:goo,gii;foo,fii " +
"TLS " +
"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 " +
"CA:car " +
"CA.Optional:true " +
"Redirect.EntryPoint:https " +
"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 ",
"ProxyProtocol.TrustedIPs:192.168.0.1 ",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
Address: ":8000",
TLS: &tls.TLS{
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"},
Certificates: tls.Certificates{
{
CertFile: tls.FileOrContent("goo"),
KeyFile: tls.FileOrContent("gii"),
},
{
CertFile: tls.FileOrContent("foo"),
KeyFile: tls.FileOrContent("fii"),
},
},
ClientCA: tls.ClientCA{
Files: tls.FilesOrContents{"car"},
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{
Insecure: false,
TrustedIPs: []string{"192.168.0.1"},
},
ForwardedHeaders: &ForwardedHeaders{
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",
},
},
// FIXME Test ServersTransport
},
},
{
name: "all parameters lowercase",
expression: "Name:foo " +
"address::8000 " +
"tls:goo,gii;foo,fii " +
"tls " +
"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 " +
"ca:car " +
"ca.Optional:true " +
"redirect.entryPoint:https " +
"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 ",
"proxyProtocol.TrustedIPs:192.168.0.1 ",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
Address: ":8000",
TLS: &tls.TLS{
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"},
Certificates: tls.Certificates{
{
CertFile: tls.FileOrContent("goo"),
KeyFile: tls.FileOrContent("gii"),
},
{
CertFile: tls.FileOrContent("foo"),
KeyFile: tls.FileOrContent("fii"),
},
},
ClientCA: tls.ClientCA{
Files: tls.FilesOrContents{"car"},
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{
Insecure: false,
TrustedIPs: []string{"192.168.0.1"},
},
ForwardedHeaders: &ForwardedHeaders{
Insecure: false,
TrustedIPs: []string{
"10.0.0.3/24",
"20.0.0.3/24",
},
},
// FIXME Test ServersTransport
},
},
{
name: "default",
expression: "Name:foo",
expectedEntryPointName: "foo",
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"},
},
},
expectedEntryPoint: &EntryPoint{},
},
{
name: "ProxyProtocol insecure true",
expression: "Name:foo ProxyProtocol.insecure:true",
expectedEntryPointName: "foo",
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",
expectedEntryPointName: "foo",
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",
expectedEntryPointName: "foo",
expectedEntryPoint: &EntryPoint{
ForwardedHeaders: &ForwardedHeaders{},
ProxyProtocol: &ProxyProtocol{
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 {

View file

@ -1,8 +1,29 @@
package static
import (
"errors"
"strings"
"time"
"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"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/tracing/datadog"
@ -10,12 +31,31 @@ import (
"github.com/containous/traefik/tracing/zipkin"
"github.com/containous/traefik/types"
"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 {
Global *Global
EntryPoints *EntryPoints
Global *Global `description:"Global configuration options" export:"true"`
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"`
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"`
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"`
// TODO
// 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"`
//
ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
}
// Global holds the global configuration.
type Global struct {
Debug bool `short:"d" description:"Enable debug mode" 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"`
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"`
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"`
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" 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"`
Debug bool `short:"d" description:"Enable debug mode" 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"`
}
// ServersTransport options to configure communication between Traefik and the servers
type ServersTransport struct {
InsecureSkipVerify bool `description:"Disable SSL certificate verification" 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"`
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"`
}
// 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"`
}
// 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.
type Tracing struct {
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"`
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
type BackendConfig struct {
Options
name string
disabledURLs []*url.URL
requestTimeout time.Duration
name string
disabledURLs []*url.URL
}
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)
}
if len(result) <= 0 {
if len(result) == 0 {
return nil, nil
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,6 @@
[log]
logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints]
[entryPoints.https]
address = ":4443"
@ -9,16 +8,11 @@ defaultEntryPoints = ["https"]
[entryPoints.https.tls.ClientCA]
files = ["fixtures/https/clientca/ca1.crt"]
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]
[file]
[providers]
[providers.file]
[Routers]
[Routers.router1]
@ -41,3 +35,16 @@ defaultEntryPoints = ["https"]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
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"
defaultEntryPoints = ["https"]
[entryPoints]
[entryPoints.https]
address = ":4443"
[entryPoints.https.tls]
[entryPoints.https.tls.ClientCA]
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]
[file]
[providers]
[providers.file]
[Routers]
[Routers.router1]
@ -40,3 +34,14 @@ defaultEntryPoints = ["https"]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
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"
defaultEntryPoints = ["https"]
[entryPoints]
[entryPoints.https]
@ -9,16 +9,12 @@ defaultEntryPoints = ["https"]
[entryPoints.https.tls.ClientCA]
files = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"]
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]
[file]
[providers]
[providers.file]
[Routers]
[Routers.router1]
Service = "service1"
@ -40,3 +36,15 @@ defaultEntryPoints = ["https"]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
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"
defaultEntryPoints = ["https"]
[entryPoints]
[entryPoints.https]
@ -13,7 +13,7 @@ defaultEntryPoints = ["https"]
[api]
[file]
fileName = "{{.DynamicConfFileName}}"
watch = true
[providers]
[providers.file]
fileName = "{{.DynamicConfFileName}}"
watch = true

View file

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

View file

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

View file

@ -1,21 +1,16 @@
[log]
logLevel = "DEBUG"
defaultEntryPoints = ["https"]
[entryPoints]
[entryPoints.https]
address = ":4443"
[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]
[file]
[providers]
[providers.file]
[Routers]
[Routers.router1]
@ -38,3 +33,14 @@ defaultEntryPoints = ["https"]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
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"
defaultEntryPoints = ["https"]
[entryPoints]
[entryPoints.https]
address = ":4443"
[entryPoints.https.tls]
[entryPoints.https.tls.defaultCertificate]
[entryPoints.https.tls.DefaultCertificate]
certFile = "fixtures/https/snitest.com.cert"
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]
[file]
[providers]
[providers.file]
[Routers]
[Routers.router1]
@ -35,3 +30,15 @@ defaultEntryPoints = ["https"]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
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"
defaultEntryPoints = ["https"]
[entryPoints]
[entryPoints.https]
@ -13,7 +13,8 @@ defaultEntryPoints = ["https"]
[api]
[file]
[providers]
[providers.file]
[Routers]
[Routers.router1]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -61,26 +61,6 @@ func (s *SimpleSuite) TestWithWebConfig(c *check.C) {
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) {
cmd, output := s.cmdTraefik("--help")
@ -180,7 +160,7 @@ func (s *SimpleSuite) TestApiOnSameEntryPoint(c *check.C) {
s.createComposeProject(c, "base")
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)
err := cmd.Start()
@ -264,7 +244,7 @@ func (s *SimpleSuite) TestDefaultEntrypointHTTP(c *check.C) {
s.createComposeProject(c, "base")
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)
err := cmd.Start()
@ -284,7 +264,7 @@ func (s *SimpleSuite) TestWithUnexistingEntrypoint(c *check.C) {
s.createComposeProject(c, "base")
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)
err := cmd.Start()
@ -304,7 +284,7 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntrypoint(c *check.C) {
s.createComposeProject(c, "base")
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)
err := cmd.Start()

View file

@ -49,7 +49,7 @@ func (s *WebsocketSuite) TestBase(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
err := cmd.Start()
@ -99,7 +99,7 @@ func (s *WebsocketSuite) TestWrongOrigin(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
err := cmd.Start()
@ -149,7 +149,7 @@ func (s *WebsocketSuite) TestOrigin(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
err := cmd.Start()
@ -210,7 +210,7 @@ func (s *WebsocketSuite) TestWrongOriginIgnoredByServer(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
err := cmd.Start()
@ -268,7 +268,7 @@ func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
err := cmd.Start()
@ -331,7 +331,7 @@ func (s *WebsocketSuite) TestBasicAuth(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
err := cmd.Start()
@ -375,7 +375,7 @@ func (s *WebsocketSuite) TestSpecificResponseFromBackend(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
err := cmd.Start()
@ -421,7 +421,7 @@ func (s *WebsocketSuite) TestURLWithURLEncodedChar(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
err := cmd.Start()
@ -476,7 +476,7 @@ func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug", "--accesslog")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug", "--accesslog")
defer display(c)
err := cmd.Start()
@ -535,7 +535,7 @@ func (s *WebsocketSuite) TestHeaderAreForwared(c *check.C) {
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
defer display(c)
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
func (ip *Checker) Contains(addr string) (bool, error) {
if len(addr) <= 0 {
if len(addr) == 0 {
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)
}
if len(result) <= 0 {
if len(result) == 0 {
return nil, nil
}

View file

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

View file

@ -6,8 +6,8 @@ import (
"strings"
"github.com/containous/traefik/old/log"
"github.com/containous/traefik/old/tls"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/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
func (p *Provider) Init(_ types.Constraints) error {
func (p *Provider) Init() error {
ctx := log.With(context.Background(), log.Str(log.ProviderName, "acme"))
logger := log.FromContext(ctx)

View file

@ -25,10 +25,10 @@ func TestGetUncheckedCertificates(t *testing.T) {
domainSafe := &safe.Safe{}
domainSafe.Set(domainMap)
// FIXME Add a test for DefaultCertificate
testCases := []struct {
desc string
dynamicCerts *safe.Safe
staticCerts *safe.Safe
resolvingDomains map[string]struct{}
acmeCertificates []*Certificate
domains []string
@ -45,12 +45,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
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"},
@ -72,12 +66,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
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"},
@ -94,12 +82,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
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"},
@ -116,12 +98,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
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"},
@ -190,7 +166,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
acmeProvider := Provider{
certificateStore: &traefiktls.CertificateStore{
DynamicCerts: test.dynamicCerts,
StaticCerts: test.staticCerts,
},
certificates: test.acmeCertificates,
resolvingDomains: test.resolvingDomains,

View file

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

View file

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

View file

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

View file

@ -3,7 +3,6 @@ package provider
import (
"github.com/containous/traefik/config"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
)
// Provider defines methods of a provider.
@ -11,5 +10,5 @@ type Provider interface {
// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
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