Remove old global config and use new static config
This commit is contained in:
parent
c39d21c178
commit
5d91c7e15c
114 changed files with 2485 additions and 3646 deletions
|
@ -1,6 +1,7 @@
|
||||||
package acme
|
package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
@ -15,8 +16,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
acmeprovider "github.com/containous/traefik/old/provider/acme"
|
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||||
"github.com/containous/traefik/old/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/xenolf/lego/acme"
|
"github.com/xenolf/lego/acme"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ func (a *Account) Init() error {
|
||||||
|
|
||||||
// NewAccount creates an account
|
// NewAccount creates an account
|
||||||
func NewAccount(email string, certs []*DomainsCertificate, keyTypeValue string) (*Account, error) {
|
func NewAccount(email string, certs []*DomainsCertificate, keyTypeValue string) (*Account, error) {
|
||||||
keyType := acmeprovider.GetKeyType(keyTypeValue)
|
keyType := acmeprovider.GetKeyType(context.Background(), keyTypeValue)
|
||||||
|
|
||||||
// Create a user. New accounts need an email and private key to start
|
// Create a user. New accounts need an email and private key to start
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
|
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||||
|
|
|
@ -22,9 +22,9 @@ import (
|
||||||
"github.com/containous/staert"
|
"github.com/containous/staert"
|
||||||
"github.com/containous/traefik/cluster"
|
"github.com/containous/traefik/cluster"
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
acmeprovider "github.com/containous/traefik/old/provider/acme"
|
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||||
"github.com/containous/traefik/old/types"
|
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
|
"github.com/containous/traefik/types"
|
||||||
"github.com/containous/traefik/version"
|
"github.com/containous/traefik/version"
|
||||||
"github.com/eapache/channels"
|
"github.com/eapache/channels"
|
||||||
"github.com/xenolf/lego/acme"
|
"github.com/xenolf/lego/acme"
|
||||||
|
@ -208,7 +208,7 @@ func (a *ACME) leadershipListener(elected bool) error {
|
||||||
needRegister = true
|
needRegister = true
|
||||||
} else if len(account.KeyType) == 0 {
|
} else if len(account.KeyType) == 0 {
|
||||||
// Set the KeyType if not already defined in the account
|
// Set the KeyType if not already defined in the account
|
||||||
account.KeyType = acmeprovider.GetKeyType(a.KeyType)
|
account.KeyType = acmeprovider.GetKeyType(context.Background(), a.KeyType)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.client, err = a.buildACMEClient(account)
|
a.client, err = a.buildACMEClient(account)
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
acmeprovider "github.com/containous/traefik/old/provider/acme"
|
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||||
"github.com/containous/traefik/old/types"
|
|
||||||
"github.com/containous/traefik/tls/generate"
|
"github.com/containous/traefik/tls/generate"
|
||||||
|
"github.com/containous/traefik/types"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/xenolf/lego/acme"
|
"github.com/xenolf/lego/acme"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/old/provider/acme"
|
"github.com/containous/traefik/provider/acme"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalStore is a store using a file as storage
|
// LocalStore is a store using a file as storage
|
||||||
|
|
|
@ -8,163 +8,77 @@ import (
|
||||||
|
|
||||||
"github.com/containous/flaeg/parse"
|
"github.com/containous/flaeg/parse"
|
||||||
"github.com/containous/traefik/acme"
|
"github.com/containous/traefik/acme"
|
||||||
"github.com/containous/traefik/old/api"
|
"github.com/containous/traefik/config/static"
|
||||||
"github.com/containous/traefik/old/configuration"
|
"github.com/containous/traefik/provider"
|
||||||
"github.com/containous/traefik/old/middlewares"
|
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||||
"github.com/containous/traefik/old/provider"
|
"github.com/containous/traefik/provider/file"
|
||||||
acmeprovider "github.com/containous/traefik/old/provider/acme"
|
|
||||||
"github.com/containous/traefik/old/provider/boltdb"
|
|
||||||
"github.com/containous/traefik/old/provider/consul"
|
|
||||||
"github.com/containous/traefik/old/provider/consulcatalog"
|
|
||||||
"github.com/containous/traefik/old/provider/docker"
|
|
||||||
"github.com/containous/traefik/old/provider/dynamodb"
|
|
||||||
"github.com/containous/traefik/old/provider/ecs"
|
|
||||||
"github.com/containous/traefik/old/provider/etcd"
|
|
||||||
"github.com/containous/traefik/old/provider/eureka"
|
|
||||||
"github.com/containous/traefik/old/provider/file"
|
|
||||||
"github.com/containous/traefik/old/provider/kubernetes"
|
|
||||||
"github.com/containous/traefik/old/provider/kv"
|
|
||||||
"github.com/containous/traefik/old/provider/marathon"
|
|
||||||
"github.com/containous/traefik/old/provider/mesos"
|
|
||||||
"github.com/containous/traefik/old/provider/rancher"
|
|
||||||
"github.com/containous/traefik/old/provider/zk"
|
|
||||||
"github.com/containous/traefik/old/types"
|
|
||||||
"github.com/containous/traefik/safe"
|
|
||||||
traefiktls "github.com/containous/traefik/tls"
|
traefiktls "github.com/containous/traefik/tls"
|
||||||
|
"github.com/containous/traefik/types"
|
||||||
"github.com/elazarl/go-bindata-assetfs"
|
"github.com/elazarl/go-bindata-assetfs"
|
||||||
"github.com/thoas/stats"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDo_globalConfiguration(t *testing.T) {
|
func TestDo_globalConfiguration(t *testing.T) {
|
||||||
|
|
||||||
config := &configuration.GlobalConfiguration{}
|
config := &static.Configuration{}
|
||||||
|
|
||||||
config.Debug = true
|
config.Global = &static.Global{
|
||||||
config.CheckNewVersion = true
|
Debug: true,
|
||||||
|
CheckNewVersion: true,
|
||||||
|
SendAnonymousUsage: true,
|
||||||
|
}
|
||||||
config.AccessLog = &types.AccessLog{
|
config.AccessLog = &types.AccessLog{
|
||||||
FilePath: "AccessLog FilePath",
|
FilePath: "AccessLog FilePath",
|
||||||
Format: "AccessLog Format",
|
Format: "AccessLog Format",
|
||||||
}
|
}
|
||||||
config.LogLevel = "LogLevel"
|
config.Log = &types.TraefikLog{
|
||||||
config.EntryPoints = configuration.EntryPoints{
|
LogLevel: "LogLevel",
|
||||||
|
FilePath: "/foo/path",
|
||||||
|
Format: "json",
|
||||||
|
}
|
||||||
|
config.EntryPoints = static.EntryPoints{
|
||||||
"foo": {
|
"foo": {
|
||||||
Address: "foo Address",
|
Address: "foo Address",
|
||||||
|
Transport: &static.EntryPointsTransport{
|
||||||
|
RespondingTimeouts: &static.RespondingTimeouts{
|
||||||
|
ReadTimeout: parse.Duration(111 * time.Second),
|
||||||
|
WriteTimeout: parse.Duration(111 * time.Second),
|
||||||
|
IdleTimeout: parse.Duration(111 * time.Second),
|
||||||
|
},
|
||||||
|
},
|
||||||
TLS: &traefiktls.TLS{
|
TLS: &traefiktls.TLS{
|
||||||
MinVersion: "foo MinVersion",
|
MinVersion: "foo MinVersion",
|
||||||
CipherSuites: []string{"foo CipherSuites 1", "foo CipherSuites 2", "foo CipherSuites 3"},
|
CipherSuites: []string{"foo CipherSuites 1", "foo CipherSuites 2", "foo CipherSuites 3"},
|
||||||
Certificates: traefiktls.Certificates{
|
|
||||||
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
|
|
||||||
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
|
||||||
},
|
|
||||||
ClientCA: traefiktls.ClientCA{
|
ClientCA: traefiktls.ClientCA{
|
||||||
Files: traefiktls.FilesOrContents{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"},
|
Files: traefiktls.FilesOrContents{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"},
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Redirect: &types.Redirect{
|
ProxyProtocol: &static.ProxyProtocol{
|
||||||
Replacement: "foo Replacement",
|
|
||||||
Regex: "foo Regex",
|
|
||||||
EntryPoint: "foo EntryPoint",
|
|
||||||
},
|
|
||||||
Auth: &types.Auth{
|
|
||||||
Basic: &types.Basic{
|
|
||||||
UsersFile: "foo Basic UsersFile",
|
|
||||||
Users: types.Users{"foo Basic Users 1", "foo Basic Users 2", "foo Basic Users 3"},
|
|
||||||
},
|
|
||||||
Digest: &types.Digest{
|
|
||||||
UsersFile: "foo Digest UsersFile",
|
|
||||||
Users: types.Users{"foo Digest Users 1", "foo Digest Users 2", "foo Digest Users 3"},
|
|
||||||
},
|
|
||||||
Forward: &types.Forward{
|
|
||||||
Address: "foo Address",
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "foo CA",
|
|
||||||
Cert: "foo Cert",
|
|
||||||
Key: "foo Key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
TrustForwardHeader: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
WhiteList: &types.WhiteList{
|
|
||||||
SourceRange: []string{
|
|
||||||
"127.0.0.1/32",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Compress: &configuration.Compress{},
|
|
||||||
ProxyProtocol: &configuration.ProxyProtocol{
|
|
||||||
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
|
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"fii": {
|
"fii": {
|
||||||
Address: "fii Address",
|
Address: "fii Address",
|
||||||
|
Transport: &static.EntryPointsTransport{
|
||||||
|
RespondingTimeouts: &static.RespondingTimeouts{
|
||||||
|
ReadTimeout: parse.Duration(111 * time.Second),
|
||||||
|
WriteTimeout: parse.Duration(111 * time.Second),
|
||||||
|
IdleTimeout: parse.Duration(111 * time.Second),
|
||||||
|
},
|
||||||
|
},
|
||||||
TLS: &traefiktls.TLS{
|
TLS: &traefiktls.TLS{
|
||||||
MinVersion: "fii MinVersion",
|
MinVersion: "fii MinVersion",
|
||||||
CipherSuites: []string{"fii CipherSuites 1", "fii CipherSuites 2", "fii CipherSuites 3"},
|
CipherSuites: []string{"fii CipherSuites 1", "fii CipherSuites 2", "fii CipherSuites 3"},
|
||||||
Certificates: traefiktls.Certificates{
|
|
||||||
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
|
|
||||||
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
|
||||||
},
|
|
||||||
ClientCA: traefiktls.ClientCA{
|
ClientCA: traefiktls.ClientCA{
|
||||||
Files: traefiktls.FilesOrContents{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"},
|
Files: traefiktls.FilesOrContents{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"},
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Redirect: &types.Redirect{
|
ProxyProtocol: &static.ProxyProtocol{
|
||||||
Replacement: "fii Replacement",
|
|
||||||
Regex: "fii Regex",
|
|
||||||
EntryPoint: "fii EntryPoint",
|
|
||||||
},
|
|
||||||
Auth: &types.Auth{
|
|
||||||
Basic: &types.Basic{
|
|
||||||
UsersFile: "fii Basic UsersFile",
|
|
||||||
Users: types.Users{"fii Basic Users 1", "fii Basic Users 2", "fii Basic Users 3"},
|
|
||||||
},
|
|
||||||
Digest: &types.Digest{
|
|
||||||
UsersFile: "fii Digest UsersFile",
|
|
||||||
Users: types.Users{"fii Digest Users 1", "fii Digest Users 2", "fii Digest Users 3"},
|
|
||||||
},
|
|
||||||
Forward: &types.Forward{
|
|
||||||
Address: "fii Address",
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "fii CA",
|
|
||||||
Cert: "fii Cert",
|
|
||||||
Key: "fii Key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
TrustForwardHeader: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
WhiteList: &types.WhiteList{
|
|
||||||
SourceRange: []string{
|
|
||||||
"127.0.0.1/32",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Compress: &configuration.Compress{},
|
|
||||||
ProxyProtocol: &configuration.ProxyProtocol{
|
|
||||||
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
|
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
config.Cluster = &types.Cluster{
|
|
||||||
Node: "Cluster Node",
|
|
||||||
Store: &types.Store{
|
|
||||||
Prefix: "Cluster Store Prefix",
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
}
|
|
||||||
config.Constraints = types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "Constraints Key 1",
|
|
||||||
Regex: "Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "Constraints Key 1",
|
|
||||||
Regex: "Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
config.ACME = &acme.ACME{
|
config.ACME = &acme.ACME{
|
||||||
Email: "acme Email",
|
Email: "acme Email",
|
||||||
Domains: []types.Domain{
|
Domains: []types.Domain{
|
||||||
|
@ -186,33 +100,26 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
// ...
|
// ...
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
config.DefaultEntryPoints = configuration.DefaultEntryPoints{"DefaultEntryPoints 1", "DefaultEntryPoints 2", "DefaultEntryPoints 3"}
|
config.Providers = &static.Providers{
|
||||||
config.ProvidersThrottleDuration = parse.Duration(666 * time.Second)
|
ProvidersThrottleDuration: parse.Duration(111 * time.Second),
|
||||||
config.MaxIdleConnsPerHost = 666
|
|
||||||
config.InsecureSkipVerify = true
|
|
||||||
config.RootCAs = traefiktls.FilesOrContents{"RootCAs 1", "RootCAs 2", "RootCAs 3"}
|
|
||||||
config.Retry = &configuration.Retry{
|
|
||||||
Attempts: 666,
|
|
||||||
}
|
}
|
||||||
config.HealthCheck = &configuration.HealthCheckConfig{
|
|
||||||
Interval: parse.Duration(666 * time.Second),
|
config.ServersTransport = &static.ServersTransport{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
RootCAs: traefiktls.FilesOrContents{"RootCAs 1", "RootCAs 2", "RootCAs 3"},
|
||||||
|
MaxIdleConnsPerHost: 111,
|
||||||
|
ForwardingTimeouts: &static.ForwardingTimeouts{
|
||||||
|
DialTimeout: parse.Duration(111 * time.Second),
|
||||||
|
ResponseHeaderTimeout: parse.Duration(111 * time.Second),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
config.API = &api.Handler{
|
|
||||||
EntryPoint: "traefik",
|
config.API = &static.API{
|
||||||
Dashboard: true,
|
EntryPoint: "traefik",
|
||||||
Debug: true,
|
Dashboard: true,
|
||||||
CurrentConfigurations: &safe.Safe{},
|
|
||||||
Statistics: &types.Statistics{
|
Statistics: &types.Statistics{
|
||||||
RecentErrors: 666,
|
RecentErrors: 111,
|
||||||
},
|
},
|
||||||
Stats: &stats.Stats{
|
|
||||||
Uptime: time.Now(),
|
|
||||||
Pid: 666,
|
|
||||||
ResponseCounts: map[string]int{"foo": 1},
|
|
||||||
TotalResponseCounts: map[string]int{"bar": 1},
|
|
||||||
TotalResponseTime: time.Now(),
|
|
||||||
},
|
|
||||||
StatsRecorder: &middlewares.StatsRecorder{},
|
|
||||||
DashboardAssets: &assetfs.AssetFS{
|
DashboardAssets: &assetfs.AssetFS{
|
||||||
Asset: func(path string) ([]byte, error) {
|
Asset: func(path string) ([]byte, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -225,48 +132,10 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Prefix: "fii",
|
Prefix: "fii",
|
||||||
},
|
},
|
||||||
|
Middlewares: []string{"first", "second"},
|
||||||
}
|
}
|
||||||
config.RespondingTimeouts = &configuration.RespondingTimeouts{
|
|
||||||
ReadTimeout: parse.Duration(666 * time.Second),
|
config.Providers.File = &file.Provider{
|
||||||
WriteTimeout: parse.Duration(666 * time.Second),
|
|
||||||
IdleTimeout: parse.Duration(666 * time.Second),
|
|
||||||
}
|
|
||||||
config.ForwardingTimeouts = &configuration.ForwardingTimeouts{
|
|
||||||
DialTimeout: parse.Duration(666 * time.Second),
|
|
||||||
ResponseHeaderTimeout: parse.Duration(666 * time.Second),
|
|
||||||
}
|
|
||||||
config.Docker = &docker.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "docker Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "docker Constraints Key 1",
|
|
||||||
Regex: "docker Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "docker Constraints Key 1",
|
|
||||||
Regex: "docker Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "docker Endpoint",
|
|
||||||
Domain: "docker Domain",
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "docker CA",
|
|
||||||
Cert: "docker Cert",
|
|
||||||
Key: "docker Key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
ExposedByDefault: true,
|
|
||||||
UseBindPortIP: true,
|
|
||||||
SwarmMode: true,
|
|
||||||
}
|
|
||||||
config.File = &file.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
BaseProvider: provider.BaseProvider{
|
||||||
Watch: true,
|
Watch: true,
|
||||||
Filename: "file Filename",
|
Filename: "file Filename",
|
||||||
|
@ -287,368 +156,8 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
Directory: "file Directory",
|
Directory: "file Directory",
|
||||||
}
|
}
|
||||||
config.Marathon = &marathon.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
// FIXME Test the other providers once they are migrated
|
||||||
Watch: true,
|
|
||||||
Filename: "marathon Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "marathon Constraints Key 1",
|
|
||||||
Regex: "marathon Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "marathon Constraints Key 1",
|
|
||||||
Regex: "marathon Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "",
|
|
||||||
Domain: "",
|
|
||||||
ExposedByDefault: true,
|
|
||||||
GroupsAsSubDomains: true,
|
|
||||||
DCOSToken: "",
|
|
||||||
MarathonLBCompatibility: true,
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "marathon CA",
|
|
||||||
Cert: "marathon Cert",
|
|
||||||
Key: "marathon Key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
DialerTimeout: parse.Duration(666 * time.Second),
|
|
||||||
KeepAlive: parse.Duration(666 * time.Second),
|
|
||||||
ForceTaskHostname: true,
|
|
||||||
Basic: &marathon.Basic{
|
|
||||||
HTTPBasicAuthUser: "marathon HTTPBasicAuthUser",
|
|
||||||
HTTPBasicPassword: "marathon HTTPBasicPassword",
|
|
||||||
},
|
|
||||||
RespectReadinessChecks: true,
|
|
||||||
}
|
|
||||||
config.ConsulCatalog = &consulcatalog.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "ConsulCatalog Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "ConsulCatalog Constraints Key 1",
|
|
||||||
Regex: "ConsulCatalog Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "ConsulCatalog Constraints Key 1",
|
|
||||||
Regex: "ConsulCatalog Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "ConsulCatalog Endpoint",
|
|
||||||
Domain: "ConsulCatalog Domain",
|
|
||||||
ExposedByDefault: true,
|
|
||||||
Prefix: "ConsulCatalog Prefix",
|
|
||||||
FrontEndRule: "ConsulCatalog FrontEndRule",
|
|
||||||
}
|
|
||||||
config.Kubernetes = &kubernetes.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "k8s Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "k8s Constraints Key 1",
|
|
||||||
Regex: "k8s Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "k8s Constraints Key 1",
|
|
||||||
Regex: "k8s Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "k8s Endpoint",
|
|
||||||
Token: "k8s Token",
|
|
||||||
CertAuthFilePath: "k8s CertAuthFilePath",
|
|
||||||
DisablePassHostHeaders: true,
|
|
||||||
Namespaces: kubernetes.Namespaces{"k8s Namespaces 1", "k8s Namespaces 2", "k8s Namespaces 3"},
|
|
||||||
LabelSelector: "k8s LabelSelector",
|
|
||||||
}
|
|
||||||
config.Mesos = &mesos.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "mesos Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "mesos Constraints Key 1",
|
|
||||||
Regex: "mesos Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "mesos Constraints Key 1",
|
|
||||||
Regex: "mesos Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "mesos Endpoint",
|
|
||||||
Domain: "mesos Domain",
|
|
||||||
ExposedByDefault: true,
|
|
||||||
GroupsAsSubDomains: true,
|
|
||||||
ZkDetectionTimeout: 666,
|
|
||||||
RefreshSeconds: 666,
|
|
||||||
IPSources: "mesos IPSources",
|
|
||||||
StateTimeoutSecond: 666,
|
|
||||||
Masters: []string{"mesos Masters 1", "mesos Masters 2", "mesos Masters 3"},
|
|
||||||
}
|
|
||||||
config.Eureka = &eureka.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "eureka Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "eureka Constraints Key 1",
|
|
||||||
Regex: "eureka Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "eureka Constraints Key 1",
|
|
||||||
Regex: "eureka Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "eureka Endpoint",
|
|
||||||
RefreshSeconds: parse.Duration(30 * time.Second),
|
|
||||||
}
|
|
||||||
config.ECS = &ecs.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "ecs Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "ecs Constraints Key 1",
|
|
||||||
Regex: "ecs Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "ecs Constraints Key 1",
|
|
||||||
Regex: "ecs Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Domain: "ecs Domain",
|
|
||||||
ExposedByDefault: true,
|
|
||||||
RefreshSeconds: 666,
|
|
||||||
Clusters: ecs.Clusters{"ecs Clusters 1", "ecs Clusters 2", "ecs Clusters 3"},
|
|
||||||
AutoDiscoverClusters: true,
|
|
||||||
Region: "ecs Region",
|
|
||||||
AccessKeyID: "ecs AccessKeyID",
|
|
||||||
SecretAccessKey: "ecs SecretAccessKey",
|
|
||||||
}
|
|
||||||
config.Rancher = &rancher.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "rancher Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "rancher Constraints Key 1",
|
|
||||||
Regex: "rancher Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "rancher Constraints Key 1",
|
|
||||||
Regex: "rancher Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
APIConfiguration: rancher.APIConfiguration{
|
|
||||||
Endpoint: "rancher Endpoint",
|
|
||||||
AccessKey: "rancher AccessKey",
|
|
||||||
SecretKey: "rancher SecretKey",
|
|
||||||
},
|
|
||||||
API: &rancher.APIConfiguration{
|
|
||||||
Endpoint: "rancher Endpoint",
|
|
||||||
AccessKey: "rancher AccessKey",
|
|
||||||
SecretKey: "rancher SecretKey",
|
|
||||||
},
|
|
||||||
Metadata: &rancher.MetadataConfiguration{
|
|
||||||
IntervalPoll: true,
|
|
||||||
Prefix: "rancher Metadata Prefix",
|
|
||||||
},
|
|
||||||
Domain: "rancher Domain",
|
|
||||||
RefreshSeconds: 666,
|
|
||||||
ExposedByDefault: true,
|
|
||||||
EnableServiceHealthFilter: true,
|
|
||||||
}
|
|
||||||
config.DynamoDB = &dynamodb.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "dynamodb Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "dynamodb Constraints Key 1",
|
|
||||||
Regex: "dynamodb Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "dynamodb Constraints Key 1",
|
|
||||||
Regex: "dynamodb Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
AccessKeyID: "dynamodb AccessKeyID",
|
|
||||||
RefreshSeconds: 666,
|
|
||||||
Region: "dynamodb Region",
|
|
||||||
SecretAccessKey: "dynamodb SecretAccessKey",
|
|
||||||
TableName: "dynamodb TableName",
|
|
||||||
Endpoint: "dynamodb Endpoint",
|
|
||||||
}
|
|
||||||
config.Etcd = &etcd.Provider{
|
|
||||||
Provider: kv.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "etcd Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "etcd Constraints Key 1",
|
|
||||||
Regex: "etcd Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "etcd Constraints Key 1",
|
|
||||||
Regex: "etcd Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "etcd Endpoint",
|
|
||||||
Prefix: "etcd Prefix",
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "etcd CA",
|
|
||||||
Cert: "etcd Cert",
|
|
||||||
Key: "etcd Key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
Username: "etcd Username",
|
|
||||||
Password: "etcd Password",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
config.Zookeeper = &zk.Provider{
|
|
||||||
Provider: kv.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "zk Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "zk Constraints Key 1",
|
|
||||||
Regex: "zk Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "zk Constraints Key 1",
|
|
||||||
Regex: "zk Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "zk Endpoint",
|
|
||||||
Prefix: "zk Prefix",
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "zk CA",
|
|
||||||
Cert: "zk Cert",
|
|
||||||
Key: "zk Key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
Username: "zk Username",
|
|
||||||
Password: "zk Password",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
config.Boltdb = &boltdb.Provider{
|
|
||||||
Provider: kv.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "boltdb Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "boltdb Constraints Key 1",
|
|
||||||
Regex: "boltdb Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "boltdb Constraints Key 1",
|
|
||||||
Regex: "boltdb Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "boltdb Endpoint",
|
|
||||||
Prefix: "boltdb Prefix",
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "boltdb CA",
|
|
||||||
Cert: "boltdb Cert",
|
|
||||||
Key: "boltdb Key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
Username: "boltdb Username",
|
|
||||||
Password: "boltdb Password",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
config.Consul = &consul.Provider{
|
|
||||||
Provider: kv.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "consul Filename",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "consul Constraints Key 1",
|
|
||||||
Regex: "consul Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "consul Constraints Key 1",
|
|
||||||
Regex: "consul Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "consul Endpoint",
|
|
||||||
Prefix: "consul Prefix",
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "consul CA",
|
|
||||||
Cert: "consul Cert",
|
|
||||||
Key: "consul Key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
Username: "consul Username",
|
|
||||||
Password: "consul Password",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanJSON, err := Do(config, true)
|
cleanJSON, err := Do(config, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -5,36 +5,19 @@ import (
|
||||||
|
|
||||||
"github.com/containous/traefik/anonymize"
|
"github.com/containous/traefik/anonymize"
|
||||||
"github.com/containous/traefik/cmd"
|
"github.com/containous/traefik/cmd"
|
||||||
"github.com/containous/traefik/old/configuration"
|
"github.com/containous/traefik/config/static"
|
||||||
"github.com/containous/traefik/old/provider/file"
|
|
||||||
"github.com/containous/traefik/old/types"
|
|
||||||
"github.com/containous/traefik/tls"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_createReport(t *testing.T) {
|
func Test_createReport(t *testing.T) {
|
||||||
traefikConfiguration := &cmd.TraefikConfiguration{
|
traefikConfiguration := &cmd.TraefikConfiguration{
|
||||||
ConfigFile: "FOO",
|
ConfigFile: "FOO",
|
||||||
GlobalConfiguration: configuration.GlobalConfiguration{
|
Configuration: static.Configuration{
|
||||||
EntryPoints: configuration.EntryPoints{
|
EntryPoints: static.EntryPoints{
|
||||||
"goo": &configuration.EntryPoint{
|
"goo": &static.EntryPoint{
|
||||||
Address: "hoo.bar",
|
Address: "hoo.bar",
|
||||||
Auth: &types.Auth{
|
|
||||||
Basic: &types.Basic{
|
|
||||||
UsersFile: "foo Basic UsersFile",
|
|
||||||
Users: types.Users{"foo Basic Users 1", "foo Basic Users 2", "foo Basic Users 3"},
|
|
||||||
},
|
|
||||||
Digest: &types.Digest{
|
|
||||||
UsersFile: "foo Digest UsersFile",
|
|
||||||
Users: types.Users{"foo Digest Users 1", "foo Digest Users 2", "foo Digest Users 3"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
File: &file.Provider{
|
|
||||||
Directory: "BAR",
|
|
||||||
},
|
|
||||||
RootCAs: tls.FilesOrContents{"fllf"},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,26 +25,21 @@ func Test_createReport(t *testing.T) {
|
||||||
assert.NoError(t, err, report)
|
assert.NoError(t, err, report)
|
||||||
|
|
||||||
// exported anonymous configuration
|
// exported anonymous configuration
|
||||||
assert.NotContains(t, "web Basic Users ", report)
|
|
||||||
assert.NotContains(t, "foo Digest Users ", report)
|
|
||||||
assert.NotContains(t, "hoo.bar", report)
|
assert.NotContains(t, "hoo.bar", report)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_anonymize_traefikConfiguration(t *testing.T) {
|
func Test_anonymize_traefikConfiguration(t *testing.T) {
|
||||||
traefikConfiguration := &cmd.TraefikConfiguration{
|
traefikConfiguration := &cmd.TraefikConfiguration{
|
||||||
ConfigFile: "FOO",
|
ConfigFile: "FOO",
|
||||||
GlobalConfiguration: configuration.GlobalConfiguration{
|
Configuration: static.Configuration{
|
||||||
EntryPoints: configuration.EntryPoints{
|
EntryPoints: static.EntryPoints{
|
||||||
"goo": &configuration.EntryPoint{
|
"goo": &static.EntryPoint{
|
||||||
Address: "hoo.bar",
|
Address: "hoo.bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
File: &file.Provider{
|
|
||||||
Directory: "BAR",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err := anonymize.Do(traefikConfiguration, true)
|
_, err := anonymize.Do(traefikConfiguration, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "hoo.bar", traefikConfiguration.GlobalConfiguration.EntryPoints["goo"].Address)
|
assert.Equal(t, "hoo.bar", traefikConfiguration.Configuration.EntryPoints["goo"].Address)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containous/flaeg/parse"
|
"github.com/containous/flaeg/parse"
|
||||||
"github.com/containous/traefik/old/api"
|
"github.com/containous/traefik/config/static"
|
||||||
"github.com/containous/traefik/old/configuration"
|
"github.com/containous/traefik/old/configuration"
|
||||||
"github.com/containous/traefik/old/middlewares/accesslog"
|
"github.com/containous/traefik/old/middlewares/accesslog"
|
||||||
"github.com/containous/traefik/old/middlewares/tracing"
|
|
||||||
"github.com/containous/traefik/old/middlewares/tracing/datadog"
|
|
||||||
"github.com/containous/traefik/old/middlewares/tracing/jaeger"
|
|
||||||
"github.com/containous/traefik/old/middlewares/tracing/zipkin"
|
|
||||||
"github.com/containous/traefik/old/ping"
|
|
||||||
"github.com/containous/traefik/old/provider/boltdb"
|
"github.com/containous/traefik/old/provider/boltdb"
|
||||||
"github.com/containous/traefik/old/provider/consul"
|
"github.com/containous/traefik/old/provider/consul"
|
||||||
"github.com/containous/traefik/old/provider/consulcatalog"
|
"github.com/containous/traefik/old/provider/consulcatalog"
|
||||||
|
@ -20,129 +15,53 @@ import (
|
||||||
"github.com/containous/traefik/old/provider/ecs"
|
"github.com/containous/traefik/old/provider/ecs"
|
||||||
"github.com/containous/traefik/old/provider/etcd"
|
"github.com/containous/traefik/old/provider/etcd"
|
||||||
"github.com/containous/traefik/old/provider/eureka"
|
"github.com/containous/traefik/old/provider/eureka"
|
||||||
"github.com/containous/traefik/old/provider/file"
|
|
||||||
"github.com/containous/traefik/old/provider/kubernetes"
|
"github.com/containous/traefik/old/provider/kubernetes"
|
||||||
"github.com/containous/traefik/old/provider/marathon"
|
"github.com/containous/traefik/old/provider/marathon"
|
||||||
"github.com/containous/traefik/old/provider/mesos"
|
"github.com/containous/traefik/old/provider/mesos"
|
||||||
"github.com/containous/traefik/old/provider/rancher"
|
"github.com/containous/traefik/old/provider/rancher"
|
||||||
"github.com/containous/traefik/old/provider/rest"
|
"github.com/containous/traefik/old/provider/rest"
|
||||||
"github.com/containous/traefik/old/provider/zk"
|
"github.com/containous/traefik/old/provider/zk"
|
||||||
"github.com/containous/traefik/old/types"
|
"github.com/containous/traefik/ping"
|
||||||
|
"github.com/containous/traefik/provider/file"
|
||||||
|
"github.com/containous/traefik/tracing/datadog"
|
||||||
|
"github.com/containous/traefik/tracing/jaeger"
|
||||||
|
"github.com/containous/traefik/tracing/zipkin"
|
||||||
|
"github.com/containous/traefik/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TraefikConfiguration holds GlobalConfiguration and other stuff
|
// TraefikConfiguration holds GlobalConfiguration and other stuff
|
||||||
type TraefikConfiguration struct {
|
type TraefikConfiguration struct {
|
||||||
configuration.GlobalConfiguration `mapstructure:",squash" export:"true"`
|
static.Configuration `mapstructure:",squash" export:"true"`
|
||||||
ConfigFile string `short:"c" description:"Configuration file to use (TOML)." export:"true"`
|
ConfigFile string `short:"c" description:"Configuration file to use (TOML)." export:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTraefikConfiguration creates a TraefikConfiguration with default values
|
||||||
|
func NewTraefikConfiguration() *TraefikConfiguration {
|
||||||
|
return &TraefikConfiguration{
|
||||||
|
Configuration: static.Configuration{
|
||||||
|
Global: &static.Global{
|
||||||
|
CheckNewVersion: true,
|
||||||
|
SendAnonymousUsage: false,
|
||||||
|
},
|
||||||
|
EntryPoints: make(static.EntryPoints),
|
||||||
|
Providers: &static.Providers{
|
||||||
|
ProvidersThrottleDuration: parse.Duration(2 * time.Second),
|
||||||
|
},
|
||||||
|
ServersTransport: &static.ServersTransport{
|
||||||
|
MaxIdleConnsPerHost: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ConfigFile: "",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTraefikDefaultPointersConfiguration creates a TraefikConfiguration with pointers default values
|
// NewTraefikDefaultPointersConfiguration creates a TraefikConfiguration with pointers default values
|
||||||
func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||||
// default Docker
|
|
||||||
var defaultDocker docker.Provider
|
|
||||||
defaultDocker.Watch = true
|
|
||||||
defaultDocker.ExposedByDefault = true
|
|
||||||
defaultDocker.Endpoint = "unix:///var/run/docker.sock"
|
|
||||||
defaultDocker.SwarmMode = false
|
|
||||||
|
|
||||||
// default File
|
// default File
|
||||||
var defaultFile file.Provider
|
var defaultFile file.Provider
|
||||||
defaultFile.Watch = true
|
defaultFile.Watch = true
|
||||||
defaultFile.Filename = "" // needs equivalent to viper.ConfigFileUsed()
|
defaultFile.Filename = "" // needs equivalent to viper.ConfigFileUsed()
|
||||||
|
|
||||||
// default Rest
|
|
||||||
var defaultRest rest.Provider
|
|
||||||
defaultRest.EntryPoint = configuration.DefaultInternalEntryPointName
|
|
||||||
|
|
||||||
// default Marathon
|
|
||||||
var defaultMarathon marathon.Provider
|
|
||||||
defaultMarathon.Watch = true
|
|
||||||
defaultMarathon.Endpoint = "http://127.0.0.1:8080"
|
|
||||||
defaultMarathon.ExposedByDefault = true
|
|
||||||
defaultMarathon.Constraints = types.Constraints{}
|
|
||||||
defaultMarathon.DialerTimeout = parse.Duration(5 * time.Second)
|
|
||||||
defaultMarathon.ResponseHeaderTimeout = parse.Duration(60 * time.Second)
|
|
||||||
defaultMarathon.TLSHandshakeTimeout = parse.Duration(5 * time.Second)
|
|
||||||
defaultMarathon.KeepAlive = parse.Duration(10 * time.Second)
|
|
||||||
|
|
||||||
// default Consul
|
|
||||||
var defaultConsul consul.Provider
|
|
||||||
defaultConsul.Watch = true
|
|
||||||
defaultConsul.Endpoint = "127.0.0.1:8500"
|
|
||||||
defaultConsul.Prefix = "traefik"
|
|
||||||
defaultConsul.Constraints = types.Constraints{}
|
|
||||||
|
|
||||||
// default CatalogProvider
|
|
||||||
var defaultConsulCatalog consulcatalog.Provider
|
|
||||||
defaultConsulCatalog.Endpoint = "127.0.0.1:8500"
|
|
||||||
defaultConsulCatalog.ExposedByDefault = true
|
|
||||||
defaultConsulCatalog.Constraints = types.Constraints{}
|
|
||||||
defaultConsulCatalog.Prefix = "traefik"
|
|
||||||
defaultConsulCatalog.FrontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
|
|
||||||
defaultConsulCatalog.Stale = false
|
|
||||||
|
|
||||||
// default Etcd
|
|
||||||
var defaultEtcd etcd.Provider
|
|
||||||
defaultEtcd.Watch = true
|
|
||||||
defaultEtcd.Endpoint = "127.0.0.1:2379"
|
|
||||||
defaultEtcd.Prefix = "/traefik"
|
|
||||||
defaultEtcd.Constraints = types.Constraints{}
|
|
||||||
|
|
||||||
// default Zookeeper
|
|
||||||
var defaultZookeeper zk.Provider
|
|
||||||
defaultZookeeper.Watch = true
|
|
||||||
defaultZookeeper.Endpoint = "127.0.0.1:2181"
|
|
||||||
defaultZookeeper.Prefix = "traefik"
|
|
||||||
defaultZookeeper.Constraints = types.Constraints{}
|
|
||||||
|
|
||||||
// default Boltdb
|
|
||||||
var defaultBoltDb boltdb.Provider
|
|
||||||
defaultBoltDb.Watch = true
|
|
||||||
defaultBoltDb.Endpoint = "127.0.0.1:4001"
|
|
||||||
defaultBoltDb.Prefix = "/traefik"
|
|
||||||
defaultBoltDb.Constraints = types.Constraints{}
|
|
||||||
|
|
||||||
// default Kubernetes
|
|
||||||
var defaultKubernetes kubernetes.Provider
|
|
||||||
defaultKubernetes.Watch = true
|
|
||||||
defaultKubernetes.Constraints = types.Constraints{}
|
|
||||||
|
|
||||||
// default Mesos
|
|
||||||
var defaultMesos mesos.Provider
|
|
||||||
defaultMesos.Watch = true
|
|
||||||
defaultMesos.Endpoint = "http://127.0.0.1:5050"
|
|
||||||
defaultMesos.ExposedByDefault = true
|
|
||||||
defaultMesos.Constraints = types.Constraints{}
|
|
||||||
defaultMesos.RefreshSeconds = 30
|
|
||||||
defaultMesos.ZkDetectionTimeout = 30
|
|
||||||
defaultMesos.StateTimeoutSecond = 30
|
|
||||||
|
|
||||||
// default ECS
|
|
||||||
var defaultECS ecs.Provider
|
|
||||||
defaultECS.Watch = true
|
|
||||||
defaultECS.ExposedByDefault = true
|
|
||||||
defaultECS.AutoDiscoverClusters = false
|
|
||||||
defaultECS.Clusters = ecs.Clusters{"default"}
|
|
||||||
defaultECS.RefreshSeconds = 15
|
|
||||||
defaultECS.Constraints = types.Constraints{}
|
|
||||||
|
|
||||||
// default Rancher
|
|
||||||
var defaultRancher rancher.Provider
|
|
||||||
defaultRancher.Watch = true
|
|
||||||
defaultRancher.ExposedByDefault = true
|
|
||||||
defaultRancher.RefreshSeconds = 15
|
|
||||||
|
|
||||||
// default DynamoDB
|
|
||||||
var defaultDynamoDB dynamodb.Provider
|
|
||||||
defaultDynamoDB.Constraints = types.Constraints{}
|
|
||||||
defaultDynamoDB.RefreshSeconds = 15
|
|
||||||
defaultDynamoDB.TableName = "traefik"
|
|
||||||
defaultDynamoDB.Watch = true
|
|
||||||
|
|
||||||
// default Eureka
|
|
||||||
var defaultEureka eureka.Provider
|
|
||||||
defaultEureka.RefreshSeconds = parse.Duration(30 * time.Second)
|
|
||||||
|
|
||||||
// default Ping
|
// default Ping
|
||||||
var defaultPing = ping.Handler{
|
var defaultPing = ping.Handler{
|
||||||
EntryPoint: "traefik",
|
EntryPoint: "traefik",
|
||||||
|
@ -167,24 +86,8 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// default HealthCheckConfig
|
|
||||||
healthCheck := configuration.HealthCheckConfig{
|
|
||||||
Interval: parse.Duration(configuration.DefaultHealthCheckInterval),
|
|
||||||
Timeout: parse.Duration(configuration.DefaultHealthCheckTimeout),
|
|
||||||
}
|
|
||||||
|
|
||||||
// default RespondingTimeouts
|
|
||||||
respondingTimeouts := configuration.RespondingTimeouts{
|
|
||||||
IdleTimeout: parse.Duration(configuration.DefaultIdleTimeout),
|
|
||||||
}
|
|
||||||
|
|
||||||
// default ForwardingTimeouts
|
|
||||||
forwardingTimeouts := configuration.ForwardingTimeouts{
|
|
||||||
DialTimeout: parse.Duration(configuration.DefaultDialTimeout),
|
|
||||||
}
|
|
||||||
|
|
||||||
// default Tracing
|
// default Tracing
|
||||||
defaultTracing := tracing.Tracing{
|
defaultTracing := static.Tracing{
|
||||||
Backend: "jaeger",
|
Backend: "jaeger",
|
||||||
ServiceName: "traefik",
|
ServiceName: "traefik",
|
||||||
SpanNameLimit: 0,
|
SpanNameLimit: 0,
|
||||||
|
@ -210,13 +113,8 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// default LifeCycle
|
|
||||||
defaultLifeCycle := configuration.LifeCycle{
|
|
||||||
GraceTimeOut: parse.Duration(configuration.DefaultGraceTimeout),
|
|
||||||
}
|
|
||||||
|
|
||||||
// default ApiConfiguration
|
// default ApiConfiguration
|
||||||
defaultAPI := api.Handler{
|
defaultAPI := static.API{
|
||||||
EntryPoint: "traefik",
|
EntryPoint: "traefik",
|
||||||
Dashboard: true,
|
Dashboard: true,
|
||||||
}
|
}
|
||||||
|
@ -245,65 +143,129 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultResolver := configuration.HostResolverConfig{
|
defaultResolver := static.HostResolverConfig{
|
||||||
CnameFlattening: false,
|
CnameFlattening: false,
|
||||||
ResolvConfig: "/etc/resolv.conf",
|
ResolvConfig: "/etc/resolv.conf",
|
||||||
ResolvDepth: 5,
|
ResolvDepth: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfiguration := configuration.GlobalConfiguration{
|
var defaultDocker docker.Provider
|
||||||
Docker: &defaultDocker,
|
defaultDocker.Watch = true
|
||||||
File: &defaultFile,
|
defaultDocker.ExposedByDefault = true
|
||||||
Rest: &defaultRest,
|
defaultDocker.Endpoint = "unix:///var/run/docker.sock"
|
||||||
Marathon: &defaultMarathon,
|
defaultDocker.SwarmMode = false
|
||||||
Consul: &defaultConsul,
|
|
||||||
ConsulCatalog: &defaultConsulCatalog,
|
// default Rest
|
||||||
Etcd: &defaultEtcd,
|
var defaultRest rest.Provider
|
||||||
Zookeeper: &defaultZookeeper,
|
defaultRest.EntryPoint = configuration.DefaultInternalEntryPointName
|
||||||
Boltdb: &defaultBoltDb,
|
|
||||||
Kubernetes: &defaultKubernetes,
|
// default Marathon
|
||||||
Mesos: &defaultMesos,
|
var defaultMarathon marathon.Provider
|
||||||
ECS: &defaultECS,
|
defaultMarathon.Watch = true
|
||||||
Rancher: &defaultRancher,
|
defaultMarathon.Endpoint = "http://127.0.0.1:8080"
|
||||||
Eureka: &defaultEureka,
|
defaultMarathon.ExposedByDefault = true
|
||||||
DynamoDB: &defaultDynamoDB,
|
defaultMarathon.DialerTimeout = parse.Duration(5 * time.Second)
|
||||||
Retry: &configuration.Retry{},
|
defaultMarathon.ResponseHeaderTimeout = parse.Duration(60 * time.Second)
|
||||||
HealthCheck: &healthCheck,
|
defaultMarathon.TLSHandshakeTimeout = parse.Duration(5 * time.Second)
|
||||||
RespondingTimeouts: &respondingTimeouts,
|
defaultMarathon.KeepAlive = parse.Duration(10 * time.Second)
|
||||||
ForwardingTimeouts: &forwardingTimeouts,
|
|
||||||
TraefikLog: &defaultTraefikLog,
|
// default Consul
|
||||||
AccessLog: &defaultAccessLog,
|
var defaultConsul consul.Provider
|
||||||
LifeCycle: &defaultLifeCycle,
|
defaultConsul.Watch = true
|
||||||
Ping: &defaultPing,
|
defaultConsul.Endpoint = "127.0.0.1:8500"
|
||||||
API: &defaultAPI,
|
defaultConsul.Prefix = "traefik"
|
||||||
Metrics: &defaultMetrics,
|
|
||||||
Tracing: &defaultTracing,
|
// default CatalogProvider
|
||||||
HostResolver: &defaultResolver,
|
var defaultConsulCatalog consulcatalog.Provider
|
||||||
|
defaultConsulCatalog.Endpoint = "127.0.0.1:8500"
|
||||||
|
defaultConsulCatalog.ExposedByDefault = true
|
||||||
|
defaultConsulCatalog.Prefix = "traefik"
|
||||||
|
defaultConsulCatalog.FrontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
|
||||||
|
defaultConsulCatalog.Stale = false
|
||||||
|
|
||||||
|
// default Etcd
|
||||||
|
var defaultEtcd etcd.Provider
|
||||||
|
defaultEtcd.Watch = true
|
||||||
|
defaultEtcd.Endpoint = "127.0.0.1:2379"
|
||||||
|
defaultEtcd.Prefix = "/traefik"
|
||||||
|
|
||||||
|
// default Zookeeper
|
||||||
|
var defaultZookeeper zk.Provider
|
||||||
|
defaultZookeeper.Watch = true
|
||||||
|
defaultZookeeper.Endpoint = "127.0.0.1:2181"
|
||||||
|
defaultZookeeper.Prefix = "traefik"
|
||||||
|
|
||||||
|
// default Boltdb
|
||||||
|
var defaultBoltDb boltdb.Provider
|
||||||
|
defaultBoltDb.Watch = true
|
||||||
|
defaultBoltDb.Endpoint = "127.0.0.1:4001"
|
||||||
|
defaultBoltDb.Prefix = "/traefik"
|
||||||
|
|
||||||
|
// default Kubernetes
|
||||||
|
var defaultKubernetes kubernetes.Provider
|
||||||
|
defaultKubernetes.Watch = true
|
||||||
|
|
||||||
|
// default Mesos
|
||||||
|
var defaultMesos mesos.Provider
|
||||||
|
defaultMesos.Watch = true
|
||||||
|
defaultMesos.Endpoint = "http://127.0.0.1:5050"
|
||||||
|
defaultMesos.ExposedByDefault = true
|
||||||
|
defaultMesos.RefreshSeconds = 30
|
||||||
|
defaultMesos.ZkDetectionTimeout = 30
|
||||||
|
defaultMesos.StateTimeoutSecond = 30
|
||||||
|
|
||||||
|
// default ECS
|
||||||
|
var defaultECS ecs.Provider
|
||||||
|
defaultECS.Watch = true
|
||||||
|
defaultECS.ExposedByDefault = true
|
||||||
|
defaultECS.AutoDiscoverClusters = false
|
||||||
|
defaultECS.Clusters = ecs.Clusters{"default"}
|
||||||
|
defaultECS.RefreshSeconds = 15
|
||||||
|
|
||||||
|
// default Rancher
|
||||||
|
var defaultRancher rancher.Provider
|
||||||
|
defaultRancher.Watch = true
|
||||||
|
defaultRancher.ExposedByDefault = true
|
||||||
|
defaultRancher.RefreshSeconds = 15
|
||||||
|
|
||||||
|
// default DynamoDB
|
||||||
|
var defaultDynamoDB dynamodb.Provider
|
||||||
|
defaultDynamoDB.RefreshSeconds = 15
|
||||||
|
defaultDynamoDB.TableName = "traefik"
|
||||||
|
defaultDynamoDB.Watch = true
|
||||||
|
|
||||||
|
// default Eureka
|
||||||
|
var defaultEureka eureka.Provider
|
||||||
|
defaultEureka.RefreshSeconds = parse.Duration(30 * time.Second)
|
||||||
|
|
||||||
|
defaultProviders := static.Providers{
|
||||||
|
File: &defaultFile,
|
||||||
|
Docker: &defaultDocker,
|
||||||
|
Rest: &defaultRest,
|
||||||
|
Marathon: &defaultMarathon,
|
||||||
|
Consul: &defaultConsul,
|
||||||
|
ConsulCatalog: &defaultConsulCatalog,
|
||||||
|
Etcd: &defaultEtcd,
|
||||||
|
Zookeeper: &defaultZookeeper,
|
||||||
|
Boltdb: &defaultBoltDb,
|
||||||
|
Kubernetes: &defaultKubernetes,
|
||||||
|
Mesos: &defaultMesos,
|
||||||
|
ECS: &defaultECS,
|
||||||
|
Rancher: &defaultRancher,
|
||||||
|
Eureka: &defaultEureka,
|
||||||
|
DynamoDB: &defaultDynamoDB,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &TraefikConfiguration{
|
return &TraefikConfiguration{
|
||||||
GlobalConfiguration: defaultConfiguration,
|
Configuration: static.Configuration{
|
||||||
}
|
Providers: &defaultProviders,
|
||||||
}
|
Log: &defaultTraefikLog,
|
||||||
|
AccessLog: &defaultAccessLog,
|
||||||
// NewTraefikConfiguration creates a TraefikConfiguration with default values
|
Ping: &defaultPing,
|
||||||
func NewTraefikConfiguration() *TraefikConfiguration {
|
API: &defaultAPI,
|
||||||
return &TraefikConfiguration{
|
Metrics: &defaultMetrics,
|
||||||
GlobalConfiguration: configuration.GlobalConfiguration{
|
Tracing: &defaultTracing,
|
||||||
EntryPoints: map[string]*configuration.EntryPoint{},
|
HostResolver: &defaultResolver,
|
||||||
Constraints: types.Constraints{},
|
|
||||||
DefaultEntryPoints: []string{"http"},
|
|
||||||
ProvidersThrottleDuration: parse.Duration(2 * time.Second),
|
|
||||||
MaxIdleConnsPerHost: 200,
|
|
||||||
HealthCheck: &configuration.HealthCheckConfig{
|
|
||||||
Interval: parse.Duration(configuration.DefaultHealthCheckInterval),
|
|
||||||
Timeout: parse.Duration(configuration.DefaultHealthCheckTimeout),
|
|
||||||
},
|
|
||||||
LifeCycle: &configuration.LifeCycle{
|
|
||||||
GraceTimeOut: parse.Duration(configuration.DefaultGraceTimeout),
|
|
||||||
},
|
|
||||||
CheckNewVersion: true,
|
|
||||||
},
|
},
|
||||||
ConfigFile: "",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/containous/flaeg"
|
"github.com/containous/flaeg"
|
||||||
"github.com/containous/traefik/cmd"
|
"github.com/containous/traefik/cmd"
|
||||||
"github.com/containous/traefik/old/configuration"
|
"github.com/containous/traefik/config/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCmd builds a new HealthCheck command
|
// NewCmd builds a new HealthCheck command
|
||||||
|
@ -29,9 +29,9 @@ func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfi
|
||||||
|
|
||||||
func runCmd(traefikConfiguration *cmd.TraefikConfiguration) func() error {
|
func runCmd(traefikConfiguration *cmd.TraefikConfiguration) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
traefikConfiguration.GlobalConfiguration.SetEffectiveConfiguration(traefikConfiguration.ConfigFile)
|
traefikConfiguration.Configuration.SetEffectiveConfiguration(traefikConfiguration.ConfigFile)
|
||||||
|
|
||||||
resp, errPing := Do(traefikConfiguration.GlobalConfiguration)
|
resp, errPing := Do(traefikConfiguration.Configuration)
|
||||||
if errPing != nil {
|
if errPing != nil {
|
||||||
fmt.Printf("Error calling healthcheck: %s\n", errPing)
|
fmt.Printf("Error calling healthcheck: %s\n", errPing)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -47,17 +47,18 @@ func runCmd(traefikConfiguration *cmd.TraefikConfiguration) func() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do try to do a healthcheck
|
// Do try to do a healthcheck
|
||||||
func Do(globalConfiguration configuration.GlobalConfiguration) (*http.Response, error) {
|
func Do(staticConfiguration static.Configuration) (*http.Response, error) {
|
||||||
if globalConfiguration.Ping == nil {
|
if staticConfiguration.Ping == nil {
|
||||||
return nil, errors.New("please enable `ping` to use health check")
|
return nil, errors.New("please enable `ping` to use health check")
|
||||||
}
|
}
|
||||||
pingEntryPoint, ok := globalConfiguration.EntryPoints[globalConfiguration.Ping.EntryPoint]
|
pingEntryPoint, ok := staticConfiguration.EntryPoints[staticConfiguration.Ping.EntryPoint]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("missing `ping` entrypoint")
|
return nil, errors.New("missing `ping` entrypoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{Timeout: 5 * time.Second}
|
client := &http.Client{Timeout: 5 * time.Second}
|
||||||
protocol := "http"
|
protocol := "http"
|
||||||
|
|
||||||
if pingEntryPoint.TLS != nil {
|
if pingEntryPoint.TLS != nil {
|
||||||
protocol = "https"
|
protocol = "https"
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
|
@ -65,6 +66,7 @@ func Do(globalConfiguration configuration.GlobalConfiguration) (*http.Response,
|
||||||
}
|
}
|
||||||
client.Transport = tr
|
client.Transport = tr
|
||||||
}
|
}
|
||||||
|
|
||||||
path := "/"
|
path := "/"
|
||||||
|
|
||||||
return client.Head(protocol + "://" + pingEntryPoint.Address + path + "ping")
|
return client.Head(protocol + "://" + pingEntryPoint.Address + path + "ping")
|
||||||
|
|
|
@ -36,21 +36,21 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
|
||||||
return fmt.Errorf("error using command storeconfig, no Key-value store defined")
|
return fmt.Errorf("error using command storeconfig, no Key-value store defined")
|
||||||
}
|
}
|
||||||
|
|
||||||
fileConfig := traefikConfiguration.GlobalConfiguration.File
|
fileConfig := traefikConfiguration.Providers.File
|
||||||
if fileConfig != nil {
|
if fileConfig != nil {
|
||||||
traefikConfiguration.GlobalConfiguration.File = nil
|
traefikConfiguration.Providers.File = nil
|
||||||
if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 {
|
if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 {
|
||||||
fileConfig.Filename = traefikConfiguration.ConfigFile
|
fileConfig.Filename = traefikConfiguration.ConfigFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration)
|
jsonConf, err := json.Marshal(traefikConfiguration.Configuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stdlog.Printf("Storing configuration: %s\n", jsonConf)
|
stdlog.Printf("Storing configuration: %s\n", jsonConf)
|
||||||
|
|
||||||
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
|
err = kv.StoreConfig(traefikConfiguration.Configuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -74,24 +74,24 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if traefikConfiguration.GlobalConfiguration.ACME != nil {
|
if traefikConfiguration.Configuration.ACME != nil {
|
||||||
account := &acme.Account{}
|
account := &acme.Account{}
|
||||||
|
|
||||||
// Migrate ACME data from file to KV store if needed
|
// Migrate ACME data from file to KV store if needed
|
||||||
if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
|
if len(traefikConfiguration.Configuration.ACME.StorageFile) > 0 {
|
||||||
account, err = migrateACMEData(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
|
account, err = migrateACMEData(traefikConfiguration.Configuration.ACME.StorageFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
accountInitialized, err := keyExists(kv, traefikConfiguration.GlobalConfiguration.ACME.Storage)
|
accountInitialized, err := keyExists(kv, traefikConfiguration.Configuration.ACME.Storage)
|
||||||
if err != nil && err != store.ErrKeyNotFound {
|
if err != nil && err != store.ErrKeyNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if ACME account object is already in kv store
|
// Check to see if ACME account object is already in kv store
|
||||||
if traefikConfiguration.GlobalConfiguration.ACME.OverrideCertificates || !accountInitialized {
|
if traefikConfiguration.Configuration.ACME.OverrideCertificates || !accountInitialized {
|
||||||
|
|
||||||
// Store the ACME Account into the KV Store
|
// Store the ACME Account into the KV Store
|
||||||
// Certificates in KV Store will be overridden
|
// Certificates in KV Store will be overridden
|
||||||
|
@ -103,7 +103,7 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
|
||||||
|
|
||||||
source := staert.KvSource{
|
source := staert.KvSource{
|
||||||
Store: kv,
|
Store: kv,
|
||||||
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
|
Prefix: traefikConfiguration.Configuration.ACME.Storage,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = source.StoreConfig(meta)
|
err = source.StoreConfig(meta)
|
||||||
|
@ -182,29 +182,29 @@ func CreateKvSource(traefikConfiguration *cmd.TraefikConfiguration) (*staert.KvS
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case traefikConfiguration.Consul != nil:
|
case traefikConfiguration.Providers.Consul != nil:
|
||||||
kvStore, err = traefikConfiguration.Consul.CreateStore()
|
kvStore, err = traefikConfiguration.Providers.Consul.CreateStore()
|
||||||
kv = &staert.KvSource{
|
kv = &staert.KvSource{
|
||||||
Store: kvStore,
|
Store: kvStore,
|
||||||
Prefix: traefikConfiguration.Consul.Prefix,
|
Prefix: traefikConfiguration.Providers.Consul.Prefix,
|
||||||
}
|
}
|
||||||
case traefikConfiguration.Etcd != nil:
|
case traefikConfiguration.Providers.Etcd != nil:
|
||||||
kvStore, err = traefikConfiguration.Etcd.CreateStore()
|
kvStore, err = traefikConfiguration.Providers.Etcd.CreateStore()
|
||||||
kv = &staert.KvSource{
|
kv = &staert.KvSource{
|
||||||
Store: kvStore,
|
Store: kvStore,
|
||||||
Prefix: traefikConfiguration.Etcd.Prefix,
|
Prefix: traefikConfiguration.Providers.Etcd.Prefix,
|
||||||
}
|
}
|
||||||
case traefikConfiguration.Zookeeper != nil:
|
case traefikConfiguration.Providers.Zookeeper != nil:
|
||||||
kvStore, err = traefikConfiguration.Zookeeper.CreateStore()
|
kvStore, err = traefikConfiguration.Providers.Zookeeper.CreateStore()
|
||||||
kv = &staert.KvSource{
|
kv = &staert.KvSource{
|
||||||
Store: kvStore,
|
Store: kvStore,
|
||||||
Prefix: traefikConfiguration.Zookeeper.Prefix,
|
Prefix: traefikConfiguration.Providers.Zookeeper.Prefix,
|
||||||
}
|
}
|
||||||
case traefikConfiguration.Boltdb != nil:
|
case traefikConfiguration.Providers.Boltdb != nil:
|
||||||
kvStore, err = traefikConfiguration.Boltdb.CreateStore()
|
kvStore, err = traefikConfiguration.Providers.Boltdb.CreateStore()
|
||||||
kv = &staert.KvSource{
|
kv = &staert.KvSource{
|
||||||
Store: kvStore,
|
Store: kvStore,
|
||||||
Prefix: traefikConfiguration.Boltdb.Prefix,
|
Prefix: traefikConfiguration.Providers.Boltdb.Prefix,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return kv, err
|
return kv, err
|
||||||
|
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
fmtlog "log"
|
fmtlog "log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -25,16 +26,15 @@ import (
|
||||||
"github.com/containous/traefik/config/static"
|
"github.com/containous/traefik/config/static"
|
||||||
"github.com/containous/traefik/job"
|
"github.com/containous/traefik/job"
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/old/configuration"
|
|
||||||
"github.com/containous/traefik/old/provider/ecs"
|
"github.com/containous/traefik/old/provider/ecs"
|
||||||
"github.com/containous/traefik/old/provider/kubernetes"
|
"github.com/containous/traefik/old/provider/kubernetes"
|
||||||
"github.com/containous/traefik/old/types"
|
oldtypes "github.com/containous/traefik/old/types"
|
||||||
"github.com/containous/traefik/provider/aggregator"
|
"github.com/containous/traefik/provider/aggregator"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/server"
|
"github.com/containous/traefik/server"
|
||||||
"github.com/containous/traefik/server/router"
|
"github.com/containous/traefik/server/router"
|
||||||
"github.com/containous/traefik/server/uuid"
|
|
||||||
traefiktls "github.com/containous/traefik/tls"
|
traefiktls "github.com/containous/traefik/tls"
|
||||||
|
"github.com/containous/traefik/types"
|
||||||
"github.com/containous/traefik/version"
|
"github.com/containous/traefik/version"
|
||||||
"github.com/coreos/go-systemd/daemon"
|
"github.com/coreos/go-systemd/daemon"
|
||||||
"github.com/elazarl/go-bindata-assetfs"
|
"github.com/elazarl/go-bindata-assetfs"
|
||||||
|
@ -43,6 +43,44 @@ import (
|
||||||
"github.com/vulcand/oxy/roundrobin"
|
"github.com/vulcand/oxy/roundrobin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// sliceOfStrings is the parser for []string
|
||||||
|
type sliceOfStrings []string
|
||||||
|
|
||||||
|
// String is the method to format the flag's value, part of the flag.Value interface.
|
||||||
|
// The String method's output will be used in diagnostics.
|
||||||
|
func (s *sliceOfStrings) String() string {
|
||||||
|
return strings.Join(*s, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set is the method to set the flag value, part of the flag.Value interface.
|
||||||
|
// Set's argument is a string to be parsed to set the flag.
|
||||||
|
// It's a comma-separated list, so we split it.
|
||||||
|
func (s *sliceOfStrings) Set(value string) error {
|
||||||
|
strings := strings.Split(value, ",")
|
||||||
|
if len(strings) == 0 {
|
||||||
|
return fmt.Errorf("bad []string format: %s", value)
|
||||||
|
}
|
||||||
|
for _, entrypoint := range strings {
|
||||||
|
*s = append(*s, entrypoint)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get return the []string
|
||||||
|
func (s *sliceOfStrings) Get() interface{} {
|
||||||
|
return *s
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValue sets the []string with val
|
||||||
|
func (s *sliceOfStrings) SetValue(val interface{}) {
|
||||||
|
*s = val.([]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type is type of the struct
|
||||||
|
func (s *sliceOfStrings) Type() string {
|
||||||
|
return "sliceOfStrings"
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// traefik config inits
|
// traefik config inits
|
||||||
traefikConfiguration := cmd.NewTraefikConfiguration()
|
traefikConfiguration := cmd.NewTraefikConfiguration()
|
||||||
|
@ -56,7 +94,7 @@ Complete documentation is available at https://traefik.io`,
|
||||||
Config: traefikConfiguration,
|
Config: traefikConfiguration,
|
||||||
DefaultPointersConfig: traefikPointersConfiguration,
|
DefaultPointersConfig: traefikPointersConfiguration,
|
||||||
Run: func() error {
|
Run: func() error {
|
||||||
runCmd(&traefikConfiguration.GlobalConfiguration, traefikConfiguration.ConfigFile)
|
runCmd(&traefikConfiguration.Configuration, traefikConfiguration.ConfigFile)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -67,8 +105,9 @@ Complete documentation is available at https://traefik.io`,
|
||||||
// init flaeg source
|
// init flaeg source
|
||||||
f := flaeg.New(traefikCmd, os.Args[1:])
|
f := flaeg.New(traefikCmd, os.Args[1:])
|
||||||
// add custom parsers
|
// add custom parsers
|
||||||
f.AddParser(reflect.TypeOf(configuration.EntryPoints{}), &configuration.EntryPoints{})
|
f.AddParser(reflect.TypeOf(static.EntryPoints{}), &static.EntryPoints{})
|
||||||
f.AddParser(reflect.TypeOf(configuration.DefaultEntryPoints{}), &configuration.DefaultEntryPoints{})
|
|
||||||
|
f.AddParser(reflect.SliceOf(reflect.TypeOf("")), &sliceOfStrings{})
|
||||||
f.AddParser(reflect.TypeOf(traefiktls.FilesOrContents{}), &traefiktls.FilesOrContents{})
|
f.AddParser(reflect.TypeOf(traefiktls.FilesOrContents{}), &traefiktls.FilesOrContents{})
|
||||||
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
|
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
|
||||||
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
||||||
|
@ -76,10 +115,16 @@ Complete documentation is available at https://traefik.io`,
|
||||||
f.AddParser(reflect.TypeOf([]types.Domain{}), &types.Domains{})
|
f.AddParser(reflect.TypeOf([]types.Domain{}), &types.Domains{})
|
||||||
f.AddParser(reflect.TypeOf(types.DNSResolvers{}), &types.DNSResolvers{})
|
f.AddParser(reflect.TypeOf(types.DNSResolvers{}), &types.DNSResolvers{})
|
||||||
f.AddParser(reflect.TypeOf(types.Buckets{}), &types.Buckets{})
|
f.AddParser(reflect.TypeOf(types.Buckets{}), &types.Buckets{})
|
||||||
|
|
||||||
f.AddParser(reflect.TypeOf(types.StatusCodes{}), &types.StatusCodes{})
|
f.AddParser(reflect.TypeOf(types.StatusCodes{}), &types.StatusCodes{})
|
||||||
f.AddParser(reflect.TypeOf(types.FieldNames{}), &types.FieldNames{})
|
f.AddParser(reflect.TypeOf(types.FieldNames{}), &types.FieldNames{})
|
||||||
f.AddParser(reflect.TypeOf(types.FieldHeaderNames{}), &types.FieldHeaderNames{})
|
f.AddParser(reflect.TypeOf(types.FieldHeaderNames{}), &types.FieldHeaderNames{})
|
||||||
|
|
||||||
|
// FIXME Remove with ACME
|
||||||
|
f.AddParser(reflect.TypeOf([]oldtypes.Domain{}), &oldtypes.Domains{})
|
||||||
|
// FIXME Remove with old providers
|
||||||
|
f.AddParser(reflect.TypeOf(oldtypes.Constraints{}), &oldtypes.Constraints{})
|
||||||
|
|
||||||
// add commands
|
// add commands
|
||||||
f.AddCommand(cmdVersion.NewCmd())
|
f.AddCommand(cmdVersion.NewCmd())
|
||||||
f.AddCommand(bug.NewCmd(traefikConfiguration, traefikPointersConfiguration))
|
f.AddCommand(bug.NewCmd(traefikConfiguration, traefikPointersConfiguration))
|
||||||
|
@ -124,19 +169,13 @@ Complete documentation is available at https://traefik.io`,
|
||||||
|
|
||||||
// if a KV Store is enable and no sub-command called in args
|
// if a KV Store is enable and no sub-command called in args
|
||||||
if kv != nil && usedCmd == traefikCmd {
|
if kv != nil && usedCmd == traefikCmd {
|
||||||
if traefikConfiguration.Cluster == nil {
|
|
||||||
traefikConfiguration.Cluster = &types.Cluster{Node: uuid.Get()}
|
|
||||||
}
|
|
||||||
if traefikConfiguration.Cluster.Store == nil {
|
|
||||||
traefikConfiguration.Cluster.Store = &types.Store{Prefix: kv.Prefix, Store: kv.Store}
|
|
||||||
}
|
|
||||||
s.AddSource(kv)
|
s.AddSource(kv)
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
_, err := s.LoadConfig()
|
_, err := s.LoadConfig()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
notify := func(err error, time time.Duration) {
|
notify := func(err error, time time.Duration) {
|
||||||
log.Errorf("Load config error: %+v, retrying in %s", err, time)
|
log.WithoutContext().Errorf("Load config error: %+v, retrying in %s", err, time)
|
||||||
}
|
}
|
||||||
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
|
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -153,84 +192,85 @@ Complete documentation is available at https://traefik.io`,
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile string) {
|
func runCmd(staticConfiguration *static.Configuration, configFile string) {
|
||||||
configureLogging(globalConfiguration)
|
configureLogging(staticConfiguration)
|
||||||
|
|
||||||
if len(configFile) > 0 {
|
if len(configFile) > 0 {
|
||||||
log.Infof("Using TOML configuration file %s", configFile)
|
log.WithoutContext().Infof("Using TOML configuration file %s", configFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
||||||
|
|
||||||
if err := roundrobin.SetDefaultWeight(0); err != nil {
|
if err := roundrobin.SetDefaultWeight(0); err != nil {
|
||||||
log.Error(err)
|
log.WithoutContext().Errorf("Could not set roundrobin default weight: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
globalConfiguration.SetEffectiveConfiguration(configFile)
|
staticConfiguration.SetEffectiveConfiguration(configFile)
|
||||||
globalConfiguration.ValidateConfiguration()
|
staticConfiguration.ValidateConfiguration()
|
||||||
|
|
||||||
log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
|
log.WithoutContext().Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
|
||||||
|
|
||||||
jsonConf, err := json.Marshal(globalConfiguration)
|
jsonConf, err := json.Marshal(staticConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.WithoutContext().Errorf("Could not marshal static configuration: %v", err)
|
||||||
log.Debugf("Global configuration loaded [struct] %#v", globalConfiguration)
|
log.WithoutContext().Debugf("Static configuration loaded [struct] %#v", staticConfiguration)
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Global configuration loaded %s", string(jsonConf))
|
log.WithoutContext().Debugf("Static configuration loaded %s", string(jsonConf))
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalConfiguration.API != nil && globalConfiguration.API.Dashboard {
|
if staticConfiguration.API != nil && staticConfiguration.API.Dashboard {
|
||||||
globalConfiguration.API.DashboardAssets = &assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"}
|
staticConfiguration.API.DashboardAssets = &assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalConfiguration.CheckNewVersion {
|
if staticConfiguration.Global.CheckNewVersion {
|
||||||
checkNewVersion()
|
checkNewVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
stats(globalConfiguration)
|
stats(staticConfiguration)
|
||||||
|
|
||||||
providerAggregator := aggregator.NewProviderAggregator(static.ConvertStaticConf(*globalConfiguration))
|
providerAggregator := aggregator.NewProviderAggregator(*staticConfiguration.Providers)
|
||||||
|
|
||||||
acmeProvider, err := globalConfiguration.InitACMEProvider()
|
acmeProvider, err := staticConfiguration.InitACMEProvider()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Unable to initialize ACME provider: %v", err)
|
log.WithoutContext().Errorf("Unable to initialize ACME provider: %v", err)
|
||||||
} else if acmeProvider != nil {
|
} else if acmeProvider != nil {
|
||||||
if err := providerAggregator.AddProvider(acmeProvider); err != nil {
|
if err := providerAggregator.AddProvider(acmeProvider); err != nil {
|
||||||
log.Errorf("Unable to add ACME provider to the providers list: %v", err)
|
log.WithoutContext().Errorf("Unable to add ACME provider to the providers list: %v", err)
|
||||||
acmeProvider = nil
|
acmeProvider = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entryPoints := map[string]server.EntryPoint{}
|
serverEntryPoints := make(server.EntryPoints)
|
||||||
staticConf := static.ConvertStaticConf(*globalConfiguration)
|
for entryPointName, config := range staticConfiguration.EntryPoints {
|
||||||
for entryPointName, config := range globalConfiguration.EntryPoints {
|
ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName))
|
||||||
factory := router.NewRouteAppenderFactory(staticConf, entryPointName, acmeProvider)
|
logger := log.FromContext(ctx)
|
||||||
entryPoint := server.EntryPoint{
|
|
||||||
RouteAppenderFactory: factory,
|
serverEntryPoint, err := server.NewEntryPoint(ctx, config)
|
||||||
Configuration: config,
|
if err != nil {
|
||||||
|
logger.Errorf("Error while building entryPoint: %v", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if acmeProvider != nil {
|
serverEntryPoint.RouteAppenderFactory = router.NewRouteAppenderFactory(*staticConfiguration, entryPointName, acmeProvider)
|
||||||
|
|
||||||
|
if acmeProvider != nil && entryPointName == acmeProvider.EntryPoint {
|
||||||
|
logger.Debugf("Setting Acme Certificate store from Entrypoint")
|
||||||
|
acmeProvider.SetCertificateStore(serverEntryPoint.Certs)
|
||||||
|
|
||||||
|
if acmeProvider.OnDemand {
|
||||||
|
serverEntryPoint.OnDemandListener = acmeProvider.ListenRequest
|
||||||
|
}
|
||||||
|
|
||||||
// TLS ALPN 01
|
// TLS ALPN 01
|
||||||
if acmeProvider.TLSChallenge != nil && acmeProvider.HTTPChallenge == nil && acmeProvider.DNSChallenge == nil {
|
if acmeProvider.TLSChallenge != nil && acmeProvider.HTTPChallenge == nil && acmeProvider.DNSChallenge == nil {
|
||||||
entryPoint.TLSALPNGetter = acmeProvider.GetTLSALPNCertificate
|
serverEntryPoint.TLSALPNGetter = acmeProvider.GetTLSALPNCertificate
|
||||||
}
|
|
||||||
|
|
||||||
if acmeProvider.OnDemand && entryPointName == acmeProvider.EntryPoint {
|
|
||||||
entryPoint.OnDemandListener = acmeProvider.ListenRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
if entryPointName == acmeProvider.EntryPoint {
|
|
||||||
entryPoint.CertificateStore = traefiktls.NewCertificateStore()
|
|
||||||
acmeProvider.SetCertificateStore(entryPoint.CertificateStore)
|
|
||||||
log.Debugf("Setting Acme Certificate store from Entrypoint: %s", entryPointName)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entryPoints[entryPointName] = entryPoint
|
serverEntryPoints[entryPointName] = serverEntryPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
svr := server.NewServer(*globalConfiguration, providerAggregator, entryPoints)
|
svr := server.NewServer(*staticConfiguration, providerAggregator, serverEntryPoints)
|
||||||
|
|
||||||
if acmeProvider != nil && acmeProvider.OnHostRule {
|
if acmeProvider != nil && acmeProvider.OnHostRule {
|
||||||
acmeProvider.SetConfigListenerChan(make(chan config.Configuration))
|
acmeProvider.SetConfigListenerChan(make(chan config.Configuration))
|
||||||
|
@ -238,46 +278,46 @@ func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile s
|
||||||
}
|
}
|
||||||
ctx := cmd.ContextWithSignal(context.Background())
|
ctx := cmd.ContextWithSignal(context.Background())
|
||||||
|
|
||||||
if staticConf.Ping != nil {
|
if staticConfiguration.Ping != nil {
|
||||||
staticConf.Ping.WithContext(ctx)
|
staticConfiguration.Ping.WithContext(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
svr.StartWithContext(ctx)
|
svr.Start(ctx)
|
||||||
defer svr.Close()
|
defer svr.Close()
|
||||||
|
|
||||||
sent, err := daemon.SdNotify(false, "READY=1")
|
sent, err := daemon.SdNotify(false, "READY=1")
|
||||||
if !sent && err != nil {
|
if !sent && err != nil {
|
||||||
log.Error("Fail to notify", err)
|
log.WithoutContext().Errorf("Failed to notify: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := daemon.SdWatchdogEnabled(false)
|
t, err := daemon.SdWatchdogEnabled(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Problem with watchdog", err)
|
log.WithoutContext().Errorf("Could not enable Watchdog: %v", err)
|
||||||
} else if t != 0 {
|
} else if t != 0 {
|
||||||
// Send a ping each half time given
|
// Send a ping each half time given
|
||||||
t = t / 2
|
t = t / 2
|
||||||
log.Info("Watchdog activated with timer each ", t)
|
log.WithoutContext().Infof("Watchdog activated with timer duration %s", t)
|
||||||
safe.Go(func() {
|
safe.Go(func() {
|
||||||
tick := time.Tick(t)
|
tick := time.Tick(t)
|
||||||
for range tick {
|
for range tick {
|
||||||
_, errHealthCheck := healthcheck.Do(*globalConfiguration)
|
_, errHealthCheck := healthcheck.Do(*staticConfiguration)
|
||||||
if globalConfiguration.Ping == nil || errHealthCheck == nil {
|
if staticConfiguration.Ping == nil || errHealthCheck == nil {
|
||||||
if ok, _ := daemon.SdNotify(false, "WATCHDOG=1"); !ok {
|
if ok, _ := daemon.SdNotify(false, "WATCHDOG=1"); !ok {
|
||||||
log.Error("Fail to tick watchdog")
|
log.WithoutContext().Error("Fail to tick watchdog")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Error(errHealthCheck)
|
log.WithoutContext().Error(errHealthCheck)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
svr.Wait()
|
svr.Wait()
|
||||||
log.Info("Shutting down")
|
log.WithoutContext().Info("Shutting down")
|
||||||
logrus.Exit(0)
|
logrus.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureLogging(globalConfiguration *configuration.GlobalConfiguration) {
|
func configureLogging(staticConfiguration *static.Configuration) {
|
||||||
// configure default log flags
|
// configure default log flags
|
||||||
fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags)
|
fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags)
|
||||||
|
|
||||||
|
@ -285,27 +325,30 @@ func configureLogging(globalConfiguration *configuration.GlobalConfiguration) {
|
||||||
// an explicitly defined log level always has precedence. if none is
|
// an explicitly defined log level always has precedence. if none is
|
||||||
// given and debug mode is disabled, the default is ERROR, and DEBUG
|
// given and debug mode is disabled, the default is ERROR, and DEBUG
|
||||||
// otherwise.
|
// otherwise.
|
||||||
levelStr := strings.ToLower(globalConfiguration.LogLevel)
|
var levelStr string
|
||||||
|
if staticConfiguration.Log != nil {
|
||||||
|
levelStr = strings.ToLower(staticConfiguration.Log.LogLevel)
|
||||||
|
}
|
||||||
if levelStr == "" {
|
if levelStr == "" {
|
||||||
levelStr = "error"
|
levelStr = "error"
|
||||||
if globalConfiguration.Debug {
|
if staticConfiguration.Global.Debug {
|
||||||
levelStr = "debug"
|
levelStr = "debug"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
level, err := logrus.ParseLevel(levelStr)
|
level, err := logrus.ParseLevel(levelStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error getting level", err)
|
log.WithoutContext().Errorf("Error getting level: %v", err)
|
||||||
}
|
}
|
||||||
log.SetLevel(level)
|
log.SetLevel(level)
|
||||||
|
|
||||||
var logFile string
|
var logFile string
|
||||||
if globalConfiguration.TraefikLog != nil && len(globalConfiguration.TraefikLog.FilePath) > 0 {
|
if staticConfiguration.Log != nil && len(staticConfiguration.Log.FilePath) > 0 {
|
||||||
logFile = globalConfiguration.TraefikLog.FilePath
|
logFile = staticConfiguration.Log.FilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure log format
|
// configure log format
|
||||||
var formatter logrus.Formatter
|
var formatter logrus.Formatter
|
||||||
if globalConfiguration.TraefikLog != nil && globalConfiguration.TraefikLog.Format == "json" {
|
if staticConfiguration.Log != nil && staticConfiguration.Log.Format == "json" {
|
||||||
formatter = &logrus.JSONFormatter{}
|
formatter = &logrus.JSONFormatter{}
|
||||||
} else {
|
} else {
|
||||||
disableColors := len(logFile) > 0
|
disableColors := len(logFile) > 0
|
||||||
|
@ -317,17 +360,17 @@ func configureLogging(globalConfiguration *configuration.GlobalConfiguration) {
|
||||||
dir := filepath.Dir(logFile)
|
dir := filepath.Dir(logFile)
|
||||||
|
|
||||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||||
log.Errorf("Failed to create log path %s: %s", dir, err)
|
log.WithoutContext().Errorf("Failed to create log path %s: %s", dir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = log.OpenFile(logFile)
|
err = log.OpenFile(logFile)
|
||||||
logrus.RegisterExitHandler(func() {
|
logrus.RegisterExitHandler(func() {
|
||||||
if err := log.CloseFile(); err != nil {
|
if err := log.CloseFile(); err != nil {
|
||||||
log.Error("Error closing log", err)
|
log.WithoutContext().Errorf("Error while closing log: %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error opening file", err)
|
log.WithoutContext().Errorf("Error while opening log file %s: %v", logFile, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,17 +384,17 @@ func checkNewVersion() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func stats(globalConfiguration *configuration.GlobalConfiguration) {
|
func stats(staticConfiguration *static.Configuration) {
|
||||||
if globalConfiguration.SendAnonymousUsage {
|
if staticConfiguration.Global.SendAnonymousUsage {
|
||||||
log.Info(`
|
log.WithoutContext().Info(`
|
||||||
Stats collection is enabled.
|
Stats collection is enabled.
|
||||||
Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.
|
Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.
|
||||||
Help us improve Traefik by leaving this feature on :)
|
Help us improve Traefik by leaving this feature on :)
|
||||||
More details on: https://docs.traefik.io/basics/#collected-data
|
More details on: https://docs.traefik.io/basics/#collected-data
|
||||||
`)
|
`)
|
||||||
collect(globalConfiguration)
|
collect(staticConfiguration)
|
||||||
} else {
|
} else {
|
||||||
log.Info(`
|
log.WithoutContext().Info(`
|
||||||
Stats collection is disabled.
|
Stats collection is disabled.
|
||||||
Help us improve Traefik by turning this feature on :)
|
Help us improve Traefik by turning this feature on :)
|
||||||
More details on: https://docs.traefik.io/basics/#collected-data
|
More details on: https://docs.traefik.io/basics/#collected-data
|
||||||
|
@ -359,12 +402,12 @@ More details on: https://docs.traefik.io/basics/#collected-data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func collect(globalConfiguration *configuration.GlobalConfiguration) {
|
func collect(staticConfiguration *static.Configuration) {
|
||||||
ticker := time.Tick(24 * time.Hour)
|
ticker := time.Tick(24 * time.Hour)
|
||||||
safe.Go(func() {
|
safe.Go(func() {
|
||||||
for time.Sleep(10 * time.Minute); ; <-ticker {
|
for time.Sleep(10 * time.Minute); ; <-ticker {
|
||||||
if err := collector.Collect(globalConfiguration); err != nil {
|
if err := collector.Collect(staticConfiguration); err != nil {
|
||||||
log.Debug(err)
|
log.WithoutContext().Debug(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containous/traefik/anonymize"
|
"github.com/containous/traefik/anonymize"
|
||||||
|
"github.com/containous/traefik/config/static"
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/old/configuration"
|
"github.com/containous/traefik/old/configuration"
|
||||||
"github.com/containous/traefik/version"
|
"github.com/containous/traefik/version"
|
||||||
|
@ -29,15 +30,15 @@ type data struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect anonymous data.
|
// Collect anonymous data.
|
||||||
func Collect(globalConfiguration *configuration.GlobalConfiguration) error {
|
func Collect(staticConfiguration *static.Configuration) error {
|
||||||
anonConfig, err := anonymize.Do(globalConfiguration, false)
|
anonConfig, err := anonymize.Do(staticConfiguration, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig)
|
log.Infof("Anonymous stats sent to %s: %s", collectorURL, anonConfig)
|
||||||
|
|
||||||
hashConf, err := hashstructure.Hash(globalConfiguration, nil)
|
hashConf, err := hashstructure.Hash(staticConfiguration, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
169
config/static/entrypoints.go
Normal file
169
config/static/entrypoints.go
Normal 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
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
package configuration
|
package static
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containous/traefik/old/types"
|
|
||||||
"github.com/containous/traefik/tls"
|
"github.com/containous/traefik/tls"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -186,277 +185,70 @@ func TestEntryPoints_Set(t *testing.T) {
|
||||||
name: "all parameters camelcase",
|
name: "all parameters camelcase",
|
||||||
expression: "Name:foo " +
|
expression: "Name:foo " +
|
||||||
"Address::8000 " +
|
"Address::8000 " +
|
||||||
"TLS:goo,gii;foo,fii " +
|
|
||||||
"TLS " +
|
"TLS " +
|
||||||
"TLS.MinVersion:VersionTLS11 " +
|
"TLS.MinVersion:VersionTLS11 " +
|
||||||
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
|
"TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
|
||||||
"CA:car " +
|
"CA:car " +
|
||||||
"CA.Optional:true " +
|
"CA.Optional:true " +
|
||||||
"Redirect.EntryPoint:https " +
|
"ProxyProtocol.TrustedIPs:192.168.0.1 ",
|
||||||
"Redirect.Regex:http://localhost/(.*) " +
|
|
||||||
"Redirect.Replacement:http://mydomain/$1 " +
|
|
||||||
"Redirect.Permanent:true " +
|
|
||||||
"Compress:true " +
|
|
||||||
"ProxyProtocol.TrustedIPs:192.168.0.1 " +
|
|
||||||
"ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24 " +
|
|
||||||
"Auth.Basic.Realm:myRealm " +
|
|
||||||
"Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 " +
|
|
||||||
"Auth.Basic.RemoveHeader:true " +
|
|
||||||
"Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
|
|
||||||
"Auth.Digest.RemoveHeader:true " +
|
|
||||||
"Auth.HeaderField:X-WebAuth-User " +
|
|
||||||
"Auth.Forward.Address:https://authserver.com/auth " +
|
|
||||||
"Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret " +
|
|
||||||
"Auth.Forward.TrustForwardHeader:true " +
|
|
||||||
"Auth.Forward.TLS.CA:path/to/local.crt " +
|
|
||||||
"Auth.Forward.TLS.CAOptional:true " +
|
|
||||||
"Auth.Forward.TLS.Cert:path/to/foo.cert " +
|
|
||||||
"Auth.Forward.TLS.Key:path/to/foo.key " +
|
|
||||||
"Auth.Forward.TLS.InsecureSkipVerify:true " +
|
|
||||||
"WhiteList.SourceRange:10.42.0.0/16,152.89.1.33/32,afed:be44::/16 " +
|
|
||||||
"WhiteList.IPStrategy.depth:3 " +
|
|
||||||
"WhiteList.IPStrategy.ExcludedIPs:10.0.0.3/24,20.0.0.3/24 " +
|
|
||||||
"ClientIPStrategy.depth:3 " +
|
|
||||||
"ClientIPStrategy.ExcludedIPs:10.0.0.3/24,20.0.0.3/24 ",
|
|
||||||
expectedEntryPointName: "foo",
|
expectedEntryPointName: "foo",
|
||||||
expectedEntryPoint: &EntryPoint{
|
expectedEntryPoint: &EntryPoint{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
TLS: &tls.TLS{
|
TLS: &tls.TLS{
|
||||||
MinVersion: "VersionTLS11",
|
MinVersion: "VersionTLS11",
|
||||||
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
|
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
|
||||||
Certificates: tls.Certificates{
|
|
||||||
{
|
|
||||||
CertFile: tls.FileOrContent("goo"),
|
|
||||||
KeyFile: tls.FileOrContent("gii"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
CertFile: tls.FileOrContent("foo"),
|
|
||||||
KeyFile: tls.FileOrContent("fii"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ClientCA: tls.ClientCA{
|
ClientCA: tls.ClientCA{
|
||||||
Files: tls.FilesOrContents{"car"},
|
Files: tls.FilesOrContents{"car"},
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Redirect: &types.Redirect{
|
|
||||||
EntryPoint: "https",
|
|
||||||
Regex: "http://localhost/(.*)",
|
|
||||||
Replacement: "http://mydomain/$1",
|
|
||||||
Permanent: true,
|
|
||||||
},
|
|
||||||
Auth: &types.Auth{
|
|
||||||
Basic: &types.Basic{
|
|
||||||
Realm: "myRealm",
|
|
||||||
RemoveHeader: true,
|
|
||||||
Users: types.Users{
|
|
||||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
|
||||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Digest: &types.Digest{
|
|
||||||
RemoveHeader: true,
|
|
||||||
Users: types.Users{
|
|
||||||
"test:traefik:a2688e031edb4be6a3797f3882655c05",
|
|
||||||
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Forward: &types.Forward{
|
|
||||||
Address: "https://authserver.com/auth",
|
|
||||||
AuthResponseHeaders: []string{"X-Auth", "X-Test", "X-Secret"},
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "path/to/local.crt",
|
|
||||||
CAOptional: true,
|
|
||||||
Cert: "path/to/foo.cert",
|
|
||||||
Key: "path/to/foo.key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
TrustForwardHeader: true,
|
|
||||||
},
|
|
||||||
HeaderField: "X-WebAuth-User",
|
|
||||||
},
|
|
||||||
WhiteList: &types.WhiteList{
|
|
||||||
SourceRange: []string{
|
|
||||||
"10.42.0.0/16",
|
|
||||||
"152.89.1.33/32",
|
|
||||||
"afed:be44::/16",
|
|
||||||
},
|
|
||||||
IPStrategy: &types.IPStrategy{
|
|
||||||
Depth: 3,
|
|
||||||
ExcludedIPs: []string{
|
|
||||||
"10.0.0.3/24",
|
|
||||||
"20.0.0.3/24",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Compress: &Compress{},
|
|
||||||
ProxyProtocol: &ProxyProtocol{
|
ProxyProtocol: &ProxyProtocol{
|
||||||
Insecure: false,
|
Insecure: false,
|
||||||
TrustedIPs: []string{"192.168.0.1"},
|
TrustedIPs: []string{"192.168.0.1"},
|
||||||
},
|
},
|
||||||
ForwardedHeaders: &ForwardedHeaders{
|
// FIXME Test ServersTransport
|
||||||
Insecure: false,
|
|
||||||
TrustedIPs: []string{
|
|
||||||
"10.0.0.3/24",
|
|
||||||
"20.0.0.3/24",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ClientIPStrategy: &types.IPStrategy{
|
|
||||||
Depth: 3,
|
|
||||||
ExcludedIPs: []string{
|
|
||||||
"10.0.0.3/24",
|
|
||||||
"20.0.0.3/24",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all parameters lowercase",
|
name: "all parameters lowercase",
|
||||||
expression: "Name:foo " +
|
expression: "Name:foo " +
|
||||||
"address::8000 " +
|
"address::8000 " +
|
||||||
"tls:goo,gii;foo,fii " +
|
|
||||||
"tls " +
|
"tls " +
|
||||||
"tls.minversion:VersionTLS11 " +
|
"tls.minversion:VersionTLS11 " +
|
||||||
"tls.ciphersuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
|
"tls.ciphersuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA " +
|
||||||
"ca:car " +
|
"ca:car " +
|
||||||
"ca.Optional:true " +
|
"ca.Optional:true " +
|
||||||
"redirect.entryPoint:https " +
|
"proxyProtocol.TrustedIPs:192.168.0.1 ",
|
||||||
"redirect.regex:http://localhost/(.*) " +
|
|
||||||
"redirect.replacement:http://mydomain/$1 " +
|
|
||||||
"redirect.permanent:true " +
|
|
||||||
"compress:true " +
|
|
||||||
"whiteList.sourceRange:10.42.0.0/16,152.89.1.33/32,afed:be44::/16 " +
|
|
||||||
"proxyProtocol.TrustedIPs:192.168.0.1 " +
|
|
||||||
"forwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24 " +
|
|
||||||
"auth.basic.realm:myRealm " +
|
|
||||||
"auth.basic.users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 " +
|
|
||||||
"auth.digest.users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
|
|
||||||
"auth.headerField:X-WebAuth-User " +
|
|
||||||
"auth.forward.address:https://authserver.com/auth " +
|
|
||||||
"auth.forward.authResponseHeaders:X-Auth,X-Test,X-Secret " +
|
|
||||||
"auth.forward.trustForwardHeader:true " +
|
|
||||||
"auth.forward.tls.ca:path/to/local.crt " +
|
|
||||||
"auth.forward.tls.caOptional:true " +
|
|
||||||
"auth.forward.tls.cert:path/to/foo.cert " +
|
|
||||||
"auth.forward.tls.key:path/to/foo.key " +
|
|
||||||
"auth.forward.tls.insecureSkipVerify:true ",
|
|
||||||
expectedEntryPointName: "foo",
|
expectedEntryPointName: "foo",
|
||||||
expectedEntryPoint: &EntryPoint{
|
expectedEntryPoint: &EntryPoint{
|
||||||
Address: ":8000",
|
Address: ":8000",
|
||||||
TLS: &tls.TLS{
|
TLS: &tls.TLS{
|
||||||
MinVersion: "VersionTLS11",
|
MinVersion: "VersionTLS11",
|
||||||
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
|
CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
|
||||||
Certificates: tls.Certificates{
|
|
||||||
{
|
|
||||||
CertFile: tls.FileOrContent("goo"),
|
|
||||||
KeyFile: tls.FileOrContent("gii"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
CertFile: tls.FileOrContent("foo"),
|
|
||||||
KeyFile: tls.FileOrContent("fii"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ClientCA: tls.ClientCA{
|
ClientCA: tls.ClientCA{
|
||||||
Files: tls.FilesOrContents{"car"},
|
Files: tls.FilesOrContents{"car"},
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Redirect: &types.Redirect{
|
|
||||||
EntryPoint: "https",
|
|
||||||
Regex: "http://localhost/(.*)",
|
|
||||||
Replacement: "http://mydomain/$1",
|
|
||||||
Permanent: true,
|
|
||||||
},
|
|
||||||
Auth: &types.Auth{
|
|
||||||
Basic: &types.Basic{
|
|
||||||
Realm: "myRealm",
|
|
||||||
Users: types.Users{
|
|
||||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
|
||||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Digest: &types.Digest{
|
|
||||||
Users: types.Users{
|
|
||||||
"test:traefik:a2688e031edb4be6a3797f3882655c05",
|
|
||||||
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Forward: &types.Forward{
|
|
||||||
Address: "https://authserver.com/auth",
|
|
||||||
AuthResponseHeaders: []string{"X-Auth", "X-Test", "X-Secret"},
|
|
||||||
TLS: &types.ClientTLS{
|
|
||||||
CA: "path/to/local.crt",
|
|
||||||
CAOptional: true,
|
|
||||||
Cert: "path/to/foo.cert",
|
|
||||||
Key: "path/to/foo.key",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
TrustForwardHeader: true,
|
|
||||||
},
|
|
||||||
HeaderField: "X-WebAuth-User",
|
|
||||||
},
|
|
||||||
WhiteList: &types.WhiteList{
|
|
||||||
SourceRange: []string{
|
|
||||||
"10.42.0.0/16",
|
|
||||||
"152.89.1.33/32",
|
|
||||||
"afed:be44::/16",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Compress: &Compress{},
|
|
||||||
ProxyProtocol: &ProxyProtocol{
|
ProxyProtocol: &ProxyProtocol{
|
||||||
Insecure: false,
|
Insecure: false,
|
||||||
TrustedIPs: []string{"192.168.0.1"},
|
TrustedIPs: []string{"192.168.0.1"},
|
||||||
},
|
},
|
||||||
ForwardedHeaders: &ForwardedHeaders{
|
// FIXME Test ServersTransport
|
||||||
Insecure: false,
|
|
||||||
TrustedIPs: []string{
|
|
||||||
"10.0.0.3/24",
|
|
||||||
"20.0.0.3/24",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "default",
|
name: "default",
|
||||||
expression: "Name:foo",
|
expression: "Name:foo",
|
||||||
expectedEntryPointName: "foo",
|
expectedEntryPointName: "foo",
|
||||||
expectedEntryPoint: &EntryPoint{
|
expectedEntryPoint: &EntryPoint{},
|
||||||
ForwardedHeaders: &ForwardedHeaders{Insecure: false},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ForwardedHeaders insecure true",
|
|
||||||
expression: "Name:foo ForwardedHeaders.insecure:true",
|
|
||||||
expectedEntryPointName: "foo",
|
|
||||||
expectedEntryPoint: &EntryPoint{
|
|
||||||
ForwardedHeaders: &ForwardedHeaders{Insecure: true},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ForwardedHeaders insecure false",
|
|
||||||
expression: "Name:foo ForwardedHeaders.insecure:false",
|
|
||||||
expectedEntryPointName: "foo",
|
|
||||||
expectedEntryPoint: &EntryPoint{
|
|
||||||
ForwardedHeaders: &ForwardedHeaders{Insecure: false},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ForwardedHeaders TrustedIPs",
|
|
||||||
expression: "Name:foo ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24",
|
|
||||||
expectedEntryPointName: "foo",
|
|
||||||
expectedEntryPoint: &EntryPoint{
|
|
||||||
ForwardedHeaders: &ForwardedHeaders{
|
|
||||||
TrustedIPs: []string{"10.0.0.3/24", "20.0.0.3/24"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ProxyProtocol insecure true",
|
name: "ProxyProtocol insecure true",
|
||||||
expression: "Name:foo ProxyProtocol.insecure:true",
|
expression: "Name:foo ProxyProtocol.insecure:true",
|
||||||
expectedEntryPointName: "foo",
|
expectedEntryPointName: "foo",
|
||||||
expectedEntryPoint: &EntryPoint{
|
expectedEntryPoint: &EntryPoint{
|
||||||
ForwardedHeaders: &ForwardedHeaders{},
|
ProxyProtocol: &ProxyProtocol{Insecure: true},
|
||||||
ProxyProtocol: &ProxyProtocol{Insecure: true},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -464,8 +256,7 @@ func TestEntryPoints_Set(t *testing.T) {
|
||||||
expression: "Name:foo ProxyProtocol.insecure:false",
|
expression: "Name:foo ProxyProtocol.insecure:false",
|
||||||
expectedEntryPointName: "foo",
|
expectedEntryPointName: "foo",
|
||||||
expectedEntryPoint: &EntryPoint{
|
expectedEntryPoint: &EntryPoint{
|
||||||
ForwardedHeaders: &ForwardedHeaders{},
|
ProxyProtocol: &ProxyProtocol{},
|
||||||
ProxyProtocol: &ProxyProtocol{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -473,30 +264,11 @@ func TestEntryPoints_Set(t *testing.T) {
|
||||||
expression: "Name:foo ProxyProtocol.TrustedIPs:10.0.0.3/24,20.0.0.3/24",
|
expression: "Name:foo ProxyProtocol.TrustedIPs:10.0.0.3/24,20.0.0.3/24",
|
||||||
expectedEntryPointName: "foo",
|
expectedEntryPointName: "foo",
|
||||||
expectedEntryPoint: &EntryPoint{
|
expectedEntryPoint: &EntryPoint{
|
||||||
ForwardedHeaders: &ForwardedHeaders{},
|
|
||||||
ProxyProtocol: &ProxyProtocol{
|
ProxyProtocol: &ProxyProtocol{
|
||||||
TrustedIPs: []string{"10.0.0.3/24", "20.0.0.3/24"},
|
TrustedIPs: []string{"10.0.0.3/24", "20.0.0.3/24"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "compress on",
|
|
||||||
expression: "Name:foo Compress:on",
|
|
||||||
expectedEntryPointName: "foo",
|
|
||||||
expectedEntryPoint: &EntryPoint{
|
|
||||||
Compress: &Compress{},
|
|
||||||
ForwardedHeaders: &ForwardedHeaders{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "compress true",
|
|
||||||
expression: "Name:foo Compress:true",
|
|
||||||
expectedEntryPointName: "foo",
|
|
||||||
expectedEntryPoint: &EntryPoint{
|
|
||||||
Compress: &Compress{},
|
|
||||||
ForwardedHeaders: &ForwardedHeaders{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
|
@ -1,8 +1,29 @@
|
||||||
package static
|
package static
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containous/flaeg/parse"
|
"github.com/containous/flaeg/parse"
|
||||||
|
"github.com/containous/traefik/acme"
|
||||||
|
"github.com/containous/traefik/log"
|
||||||
|
"github.com/containous/traefik/old/provider/boltdb"
|
||||||
|
"github.com/containous/traefik/old/provider/consul"
|
||||||
|
"github.com/containous/traefik/old/provider/consulcatalog"
|
||||||
|
"github.com/containous/traefik/old/provider/docker"
|
||||||
|
"github.com/containous/traefik/old/provider/dynamodb"
|
||||||
|
"github.com/containous/traefik/old/provider/ecs"
|
||||||
|
"github.com/containous/traefik/old/provider/etcd"
|
||||||
|
"github.com/containous/traefik/old/provider/eureka"
|
||||||
|
"github.com/containous/traefik/old/provider/kubernetes"
|
||||||
|
"github.com/containous/traefik/old/provider/marathon"
|
||||||
|
"github.com/containous/traefik/old/provider/mesos"
|
||||||
|
"github.com/containous/traefik/old/provider/rancher"
|
||||||
|
"github.com/containous/traefik/old/provider/rest"
|
||||||
|
"github.com/containous/traefik/old/provider/zk"
|
||||||
"github.com/containous/traefik/ping"
|
"github.com/containous/traefik/ping"
|
||||||
|
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||||
"github.com/containous/traefik/provider/file"
|
"github.com/containous/traefik/provider/file"
|
||||||
"github.com/containous/traefik/tls"
|
"github.com/containous/traefik/tls"
|
||||||
"github.com/containous/traefik/tracing/datadog"
|
"github.com/containous/traefik/tracing/datadog"
|
||||||
|
@ -10,12 +31,31 @@ import (
|
||||||
"github.com/containous/traefik/tracing/zipkin"
|
"github.com/containous/traefik/tracing/zipkin"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/elazarl/go-bindata-assetfs"
|
"github.com/elazarl/go-bindata-assetfs"
|
||||||
|
lego "github.com/xenolf/lego/acme"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configuration FIXME temp static configuration
|
const (
|
||||||
|
// DefaultInternalEntryPointName the name of the default internal entry point
|
||||||
|
DefaultInternalEntryPointName = "traefik"
|
||||||
|
|
||||||
|
// DefaultGraceTimeout controls how long Traefik serves pending requests
|
||||||
|
// prior to shutting down.
|
||||||
|
DefaultGraceTimeout = 10 * time.Second
|
||||||
|
|
||||||
|
// DefaultIdleTimeout before closing an idle connection.
|
||||||
|
DefaultIdleTimeout = 180 * time.Second
|
||||||
|
|
||||||
|
// DefaultAcmeCAServer is the default ACME API endpoint
|
||||||
|
DefaultAcmeCAServer = "https://acme-v02.api.letsencrypt.org/directory"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Configuration is the static configuration
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Global *Global
|
Global *Global `description:"Global configuration options" export:"true"`
|
||||||
EntryPoints *EntryPoints
|
|
||||||
|
ServersTransport *ServersTransport `description:"Servers default transport" export:"true"`
|
||||||
|
EntryPoints EntryPoints `description:"Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key;prod/traefik.crt,prod/traefik.key'" export:"true"`
|
||||||
|
Providers *Providers `description:"Providers configuration" export:"true"`
|
||||||
|
|
||||||
API *API `description:"Enable api/dashboard" export:"true"`
|
API *API `description:"Enable api/dashboard" export:"true"`
|
||||||
Metrics *types.Metrics `description:"Enable a metrics exporter" export:"true"`
|
Metrics *types.Metrics `description:"Enable a metrics exporter" export:"true"`
|
||||||
|
@ -26,31 +66,24 @@ type Configuration struct {
|
||||||
AccessLog *types.AccessLog `description:"Access log settings" export:"true"`
|
AccessLog *types.AccessLog `description:"Access log settings" export:"true"`
|
||||||
Tracing *Tracing `description:"OpenTracing configuration" export:"true"`
|
Tracing *Tracing `description:"OpenTracing configuration" export:"true"`
|
||||||
|
|
||||||
File *file.Provider `description:"Enable File backend with default settings" export:"true"`
|
|
||||||
Constraints types.Constraints `description:"Filter services by constraint, matching with service tags" export:"true"`
|
|
||||||
|
|
||||||
HostResolver *HostResolverConfig `description:"Enable CNAME Flattening" export:"true"`
|
HostResolver *HostResolverConfig `description:"Enable CNAME Flattening" export:"true"`
|
||||||
|
|
||||||
// TODO
|
ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
|
||||||
// ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
|
|
||||||
// Retry *Retry `description:"Enable retry sending request if network error" export:"true"`
|
|
||||||
// HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"`
|
|
||||||
//
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global holds the global configuration.
|
// Global holds the global configuration.
|
||||||
type Global struct {
|
type Global struct {
|
||||||
Debug bool `short:"d" description:"Enable debug mode" export:"true"`
|
Debug bool `short:"d" description:"Enable debug mode" export:"true"`
|
||||||
CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"`
|
CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"`
|
||||||
SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"`
|
SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"`
|
||||||
InsecureSkipVerify bool `description:"Disable SSL certificate verification" export:"true"`
|
}
|
||||||
RootCAs tls.FilesOrContents `description:"Add cert file for self-signed certificate"`
|
|
||||||
ProvidersThrottleDuration parse.Duration `description:"Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time." export:"true"`
|
// ServersTransport options to configure communication between Traefik and the servers
|
||||||
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"`
|
type ServersTransport struct {
|
||||||
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
|
InsecureSkipVerify bool `description:"Disable SSL certificate verification" export:"true"`
|
||||||
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"`
|
RootCAs tls.FilesOrContents `description:"Add cert file for self-signed certificate"`
|
||||||
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" export:"true"`
|
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" export:"true"`
|
||||||
|
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// API holds the API configuration
|
// API holds the API configuration
|
||||||
|
@ -81,20 +114,6 @@ type LifeCycle struct {
|
||||||
GraceTimeOut parse.Duration `description:"Duration to give active requests a chance to finish before Traefik stops"`
|
GraceTimeOut parse.Duration `description:"Duration to give active requests a chance to finish before Traefik stops"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EntryPoint holds the entry point configuration
|
|
||||||
type EntryPoint struct {
|
|
||||||
Address string
|
|
||||||
}
|
|
||||||
|
|
||||||
// EntryPointList holds the HTTP entry point list type.
|
|
||||||
type EntryPointList map[string]EntryPoint
|
|
||||||
|
|
||||||
// EntryPoints holds the entry points configuration.
|
|
||||||
type EntryPoints struct {
|
|
||||||
EntryPointList
|
|
||||||
Defaults []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tracing holds the tracing configuration.
|
// Tracing holds the tracing configuration.
|
||||||
type Tracing struct {
|
type Tracing struct {
|
||||||
Backend string `description:"Selects the tracking backend ('jaeger','zipkin', 'datadog')." export:"true"`
|
Backend string `description:"Selects the tracking backend ('jaeger','zipkin', 'datadog')." export:"true"`
|
||||||
|
@ -111,3 +130,276 @@ type HostResolverConfig struct {
|
||||||
ResolvConfig string `description:"resolv.conf used for DNS resolving" export:"true"`
|
ResolvConfig string `description:"resolv.conf used for DNS resolving" export:"true"`
|
||||||
ResolvDepth int `description:"The maximal depth of DNS recursive resolving" export:"true"`
|
ResolvDepth int `description:"The maximal depth of DNS recursive resolving" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Providers contains providers configuration
|
||||||
|
type Providers struct {
|
||||||
|
ProvidersThrottleDuration parse.Duration `description:"Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time." export:"true"`
|
||||||
|
Docker *docker.Provider `description:"Enable Docker backend with default settings" export:"true"`
|
||||||
|
File *file.Provider `description:"Enable File backend with default settings" export:"true"`
|
||||||
|
Marathon *marathon.Provider `description:"Enable Marathon backend with default settings" export:"true"`
|
||||||
|
Consul *consul.Provider `description:"Enable Consul backend with default settings" export:"true"`
|
||||||
|
ConsulCatalog *consulcatalog.Provider `description:"Enable Consul catalog backend with default settings" export:"true"`
|
||||||
|
Etcd *etcd.Provider `description:"Enable Etcd backend with default settings" export:"true"`
|
||||||
|
Zookeeper *zk.Provider `description:"Enable Zookeeper backend with default settings" export:"true"`
|
||||||
|
Boltdb *boltdb.Provider `description:"Enable Boltdb backend with default settings" export:"true"`
|
||||||
|
Kubernetes *kubernetes.Provider `description:"Enable Kubernetes backend with default settings" export:"true"`
|
||||||
|
Mesos *mesos.Provider `description:"Enable Mesos backend with default settings" export:"true"`
|
||||||
|
Eureka *eureka.Provider `description:"Enable Eureka backend with default settings" export:"true"`
|
||||||
|
ECS *ecs.Provider `description:"Enable ECS backend with default settings" export:"true"`
|
||||||
|
Rancher *rancher.Provider `description:"Enable Rancher backend with default settings" export:"true"`
|
||||||
|
DynamoDB *dynamodb.Provider `description:"Enable DynamoDB backend with default settings" export:"true"`
|
||||||
|
Rest *rest.Provider `description:"Enable Rest backend with default settings" export:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEffectiveConfiguration adds missing configuration parameters derived from existing ones.
|
||||||
|
// It also takes care of maintaining backwards compatibility.
|
||||||
|
func (c *Configuration) SetEffectiveConfiguration(configFile string) {
|
||||||
|
if len(c.EntryPoints) == 0 {
|
||||||
|
c.EntryPoints = EntryPoints{
|
||||||
|
"http": &EntryPoint{
|
||||||
|
Address: ":80",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.API != nil && c.API.EntryPoint == DefaultInternalEntryPointName) ||
|
||||||
|
(c.Ping != nil && c.Ping.EntryPoint == DefaultInternalEntryPointName) ||
|
||||||
|
(c.Metrics != nil && c.Metrics.Prometheus != nil && c.Metrics.Prometheus.EntryPoint == DefaultInternalEntryPointName) ||
|
||||||
|
(c.Providers.Rest != nil && c.Providers.Rest.EntryPoint == DefaultInternalEntryPointName) {
|
||||||
|
if _, ok := c.EntryPoints[DefaultInternalEntryPointName]; !ok {
|
||||||
|
c.EntryPoints[DefaultInternalEntryPointName] = &EntryPoint{Address: ":8080"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entryPoint := range c.EntryPoints {
|
||||||
|
if entryPoint.Transport == nil {
|
||||||
|
entryPoint.Transport = &EntryPointsTransport{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure LifeCycle isn't nil to spare nil checks elsewhere.
|
||||||
|
if entryPoint.Transport.LifeCycle == nil {
|
||||||
|
entryPoint.Transport.LifeCycle = &LifeCycle{
|
||||||
|
GraceTimeOut: parse.Duration(DefaultGraceTimeout),
|
||||||
|
}
|
||||||
|
entryPoint.Transport.RespondingTimeouts = &RespondingTimeouts{
|
||||||
|
IdleTimeout: parse.Duration(DefaultIdleTimeout),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Providers.Rancher != nil {
|
||||||
|
// Ensure backwards compatibility for now
|
||||||
|
if len(c.Providers.Rancher.AccessKey) > 0 ||
|
||||||
|
len(c.Providers.Rancher.Endpoint) > 0 ||
|
||||||
|
len(c.Providers.Rancher.SecretKey) > 0 {
|
||||||
|
|
||||||
|
if c.Providers.Rancher.API == nil {
|
||||||
|
c.Providers.Rancher.API = &rancher.APIConfiguration{
|
||||||
|
AccessKey: c.Providers.Rancher.AccessKey,
|
||||||
|
SecretKey: c.Providers.Rancher.SecretKey,
|
||||||
|
Endpoint: c.Providers.Rancher.Endpoint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Warn("Deprecated configuration found: rancher.[accesskey|secretkey|endpoint]. " +
|
||||||
|
"Please use rancher.api.[accesskey|secretkey|endpoint] instead.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Providers.Rancher.Metadata != nil && len(c.Providers.Rancher.Metadata.Prefix) == 0 {
|
||||||
|
c.Providers.Rancher.Metadata.Prefix = "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Providers.File != nil {
|
||||||
|
c.Providers.File.TraefikFile = configFile
|
||||||
|
}
|
||||||
|
|
||||||
|
c.initACMEProvider()
|
||||||
|
c.initTracing()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) initTracing() {
|
||||||
|
if c.Tracing != nil {
|
||||||
|
switch c.Tracing.Backend {
|
||||||
|
case jaeger.Name:
|
||||||
|
if c.Tracing.Jaeger == nil {
|
||||||
|
c.Tracing.Jaeger = &jaeger.Config{
|
||||||
|
SamplingServerURL: "http://localhost:5778/sampling",
|
||||||
|
SamplingType: "const",
|
||||||
|
SamplingParam: 1.0,
|
||||||
|
LocalAgentHostPort: "127.0.0.1:6831",
|
||||||
|
Propagation: "jaeger",
|
||||||
|
Gen128Bit: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Tracing.Zipkin != nil {
|
||||||
|
log.Warn("Zipkin configuration will be ignored")
|
||||||
|
c.Tracing.Zipkin = nil
|
||||||
|
}
|
||||||
|
if c.Tracing.DataDog != nil {
|
||||||
|
log.Warn("DataDog configuration will be ignored")
|
||||||
|
c.Tracing.DataDog = nil
|
||||||
|
}
|
||||||
|
case zipkin.Name:
|
||||||
|
if c.Tracing.Zipkin == nil {
|
||||||
|
c.Tracing.Zipkin = &zipkin.Config{
|
||||||
|
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
|
||||||
|
SameSpan: false,
|
||||||
|
ID128Bit: true,
|
||||||
|
Debug: false,
|
||||||
|
SampleRate: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Tracing.Jaeger != nil {
|
||||||
|
log.Warn("Jaeger configuration will be ignored")
|
||||||
|
c.Tracing.Jaeger = nil
|
||||||
|
}
|
||||||
|
if c.Tracing.DataDog != nil {
|
||||||
|
log.Warn("DataDog configuration will be ignored")
|
||||||
|
c.Tracing.DataDog = nil
|
||||||
|
}
|
||||||
|
case datadog.Name:
|
||||||
|
if c.Tracing.DataDog == nil {
|
||||||
|
c.Tracing.DataDog = &datadog.Config{
|
||||||
|
LocalAgentHostPort: "localhost:8126",
|
||||||
|
GlobalTag: "",
|
||||||
|
Debug: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Tracing.Zipkin != nil {
|
||||||
|
log.Warn("Zipkin configuration will be ignored")
|
||||||
|
c.Tracing.Zipkin = nil
|
||||||
|
}
|
||||||
|
if c.Tracing.Jaeger != nil {
|
||||||
|
log.Warn("Jaeger configuration will be ignored")
|
||||||
|
c.Tracing.Jaeger = nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Warnf("Unknown tracer %q", c.Tracing.Backend)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME handle on new configuration ACME struct
|
||||||
|
func (c *Configuration) initACMEProvider() {
|
||||||
|
if c.ACME != nil {
|
||||||
|
c.ACME.CAServer = getSafeACMECAServer(c.ACME.CAServer)
|
||||||
|
|
||||||
|
if c.ACME.DNSChallenge != nil && c.ACME.HTTPChallenge != nil {
|
||||||
|
log.Warn("Unable to use DNS challenge and HTTP challenge at the same time. Fallback to DNS challenge.")
|
||||||
|
c.ACME.HTTPChallenge = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ACME.DNSChallenge != nil && c.ACME.TLSChallenge != nil {
|
||||||
|
log.Warn("Unable to use DNS challenge and TLS challenge at the same time. Fallback to DNS challenge.")
|
||||||
|
c.ACME.TLSChallenge = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ACME.HTTPChallenge != nil && c.ACME.TLSChallenge != nil {
|
||||||
|
log.Warn("Unable to use HTTP challenge and TLS challenge at the same time. Fallback to TLS challenge.")
|
||||||
|
c.ACME.HTTPChallenge = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ACME.OnDemand {
|
||||||
|
log.Warn("ACME.OnDemand is deprecated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitACMEProvider create an acme provider from the ACME part of globalConfiguration
|
||||||
|
func (c *Configuration) InitACMEProvider() (*acmeprovider.Provider, error) {
|
||||||
|
if c.ACME != nil {
|
||||||
|
if len(c.ACME.Storage) == 0 {
|
||||||
|
// Delete the ACME configuration to avoid starting ACME in cluster mode
|
||||||
|
c.ACME = nil
|
||||||
|
return nil, errors.New("unable to initialize ACME provider with no storage location for the certificates")
|
||||||
|
}
|
||||||
|
provider := &acmeprovider.Provider{}
|
||||||
|
provider.Configuration = convertACMEChallenge(c.ACME)
|
||||||
|
|
||||||
|
store := acmeprovider.NewLocalStore(provider.Storage)
|
||||||
|
provider.Store = store
|
||||||
|
acme.ConvertToNewFormat(provider.Storage)
|
||||||
|
c.ACME = nil
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateConfiguration validate that configuration is coherent
|
||||||
|
func (c *Configuration) ValidateConfiguration() {
|
||||||
|
if c.ACME != nil {
|
||||||
|
if _, ok := c.EntryPoints[c.ACME.EntryPoint]; !ok {
|
||||||
|
log.Fatalf("Unknown entrypoint %q for ACME configuration", c.ACME.EntryPoint)
|
||||||
|
} else {
|
||||||
|
if c.EntryPoints[c.ACME.EntryPoint].TLS == nil {
|
||||||
|
log.Fatalf("Entrypoint %q has no TLS configuration for ACME configuration", c.ACME.EntryPoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSafeACMECAServer(caServerSrc string) string {
|
||||||
|
if len(caServerSrc) == 0 {
|
||||||
|
return DefaultAcmeCAServer
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(caServerSrc, "https://acme-v01.api.letsencrypt.org") {
|
||||||
|
caServer := strings.Replace(caServerSrc, "v01", "v02", 1)
|
||||||
|
log.Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer)
|
||||||
|
return caServer
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(caServerSrc, "https://acme-staging.api.letsencrypt.org") {
|
||||||
|
caServer := strings.Replace(caServerSrc, "https://acme-staging.api.letsencrypt.org", "https://acme-staging-v02.api.letsencrypt.org", 1)
|
||||||
|
log.Warnf("The CA server %[1]q refers to a v01 endpoint of the ACME API, please change to %[2]q. Fallback to %[2]q.", caServerSrc, caServer)
|
||||||
|
return caServer
|
||||||
|
}
|
||||||
|
|
||||||
|
return caServerSrc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
|
func convertACMEChallenge(oldACMEChallenge *acme.ACME) *acmeprovider.Configuration {
|
||||||
|
conf := &acmeprovider.Configuration{
|
||||||
|
KeyType: oldACMEChallenge.KeyType,
|
||||||
|
OnHostRule: oldACMEChallenge.OnHostRule,
|
||||||
|
OnDemand: oldACMEChallenge.OnDemand,
|
||||||
|
Email: oldACMEChallenge.Email,
|
||||||
|
Storage: oldACMEChallenge.Storage,
|
||||||
|
ACMELogging: oldACMEChallenge.ACMELogging,
|
||||||
|
CAServer: oldACMEChallenge.CAServer,
|
||||||
|
EntryPoint: oldACMEChallenge.EntryPoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range oldACMEChallenge.Domains {
|
||||||
|
if domain.Main != lego.UnFqdn(domain.Main) {
|
||||||
|
log.Warnf("FQDN detected, please remove the trailing dot: %s", domain.Main)
|
||||||
|
}
|
||||||
|
for _, san := range domain.SANs {
|
||||||
|
if san != lego.UnFqdn(san) {
|
||||||
|
log.Warnf("FQDN detected, please remove the trailing dot: %s", san)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conf.Domains = append(conf.Domains, domain)
|
||||||
|
}
|
||||||
|
if oldACMEChallenge.HTTPChallenge != nil {
|
||||||
|
conf.HTTPChallenge = &acmeprovider.HTTPChallenge{
|
||||||
|
EntryPoint: oldACMEChallenge.HTTPChallenge.EntryPoint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldACMEChallenge.DNSChallenge != nil {
|
||||||
|
conf.DNSChallenge = &acmeprovider.DNSChallenge{
|
||||||
|
Provider: oldACMEChallenge.DNSChallenge.Provider,
|
||||||
|
DelayBeforeCheck: oldACMEChallenge.DNSChallenge.DelayBeforeCheck,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldACMEChallenge.TLSChallenge != nil {
|
||||||
|
conf.TLSChallenge = &acmeprovider.TLSChallenge{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf
|
||||||
|
}
|
||||||
|
|
|
@ -53,9 +53,8 @@ func (opt Options) String() string {
|
||||||
// BackendConfig HealthCheck configuration for a backend
|
// BackendConfig HealthCheck configuration for a backend
|
||||||
type BackendConfig struct {
|
type BackendConfig struct {
|
||||||
Options
|
Options
|
||||||
name string
|
name string
|
||||||
disabledURLs []*url.URL
|
disabledURLs []*url.URL
|
||||||
requestTimeout time.Duration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) {
|
func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) {
|
||||||
|
|
|
@ -93,7 +93,7 @@ func cnameResolve(host string, resolvPath string) (*cnameResolv, error) {
|
||||||
result = append(result, tempRecord)
|
result = append(result, tempRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result) <= 0 {
|
if len(result) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
[log]
|
||||||
logLevel = "ERROR"
|
logLevel = "ERROR"
|
||||||
defaultEntryPoints = ["http"]
|
filePath = "traefik.log"
|
||||||
checkNewVersion = false
|
|
||||||
|
|
||||||
[traefikLog]
|
[global]
|
||||||
filePath = "traefik.log"
|
checkNewVersion = false
|
||||||
|
|
||||||
[accessLog]
|
[accessLog]
|
||||||
filePath = "access.log"
|
filePath = "access.log"
|
||||||
|
@ -36,7 +36,8 @@ checkNewVersion = false
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[docker]
|
[providers]
|
||||||
exposedByDefault = false
|
[providers.docker]
|
||||||
domain = "docker.local"
|
exposedByDefault = false
|
||||||
watch = true
|
domain = "docker.local"
|
||||||
|
watch = true
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -38,7 +39,8 @@ defaultEntryPoints = ["http", "https"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[services]
|
[services]
|
||||||
[services.test.loadbalancer]
|
[services.test.loadbalancer]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -35,7 +36,8 @@ defaultEntryPoints = ["http", "https"]
|
||||||
[web]
|
[web]
|
||||||
path="/traefik"
|
path="/traefik"
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[services]
|
[services]
|
||||||
[services.test.loadbalancer]
|
[services.test.loadbalancer]
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = "{{ .PortHTTP }}"
|
address = "{{ .PortHTTP }}"
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = "{{ .PortHTTPS }}"
|
address = "{{ .PortHTTPS }}"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
[[entryPoints.https.tls.certificates]]
|
[entryPoints.https.tls.DefaultCertificate]
|
||||||
certFile = "fixtures/acme/ssl/wildcard.crt"
|
certFile = "fixtures/acme/ssl/wildcard.crt"
|
||||||
keyFile = "fixtures/acme/ssl/wildcard.key"
|
keyFile = "fixtures/acme/ssl/wildcard.key"
|
||||||
|
|
||||||
|
@ -41,7 +40,8 @@ defaultEntryPoints = ["http", "https"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[services]
|
[services]
|
||||||
[services.test.loadbalancer]
|
[services.test.loadbalancer]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -34,6 +34,7 @@ defaultEntryPoints = ["http", "https"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
filename = "fixtures/acme/certificates.toml"
|
[providers.file]
|
||||||
watch = true
|
filename = "fixtures/acme/certificates.toml"
|
||||||
|
watch = true
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -11,7 +11,7 @@ defaultEntryPoints = ["http", "https"]
|
||||||
[entryPoints.traefik]
|
[entryPoints.traefik]
|
||||||
address = ":9000"
|
address = ":9000"
|
||||||
[entryPoints.traefik.tls]
|
[entryPoints.traefik.tls]
|
||||||
[[entryPoints.traefik.tls.certificates]]
|
[entryPoints.traefik.tls.DefaultCertificate]
|
||||||
certFile = "fixtures/acme/ssl/wildcard.crt"
|
certFile = "fixtures/acme/ssl/wildcard.crt"
|
||||||
keyFile = "fixtures/acme/ssl/wildcard.key"
|
keyFile = "fixtures/acme/ssl/wildcard.key"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -9,10 +8,11 @@ logLevel = "DEBUG"
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
|
|
||||||
|
|
||||||
[consul]
|
[providers]
|
||||||
endpoint = "{{.ConsulHost}}:8500"
|
[providers.consul]
|
||||||
watch = true
|
endpoint = "{{.ConsulHost}}:8500"
|
||||||
prefix = "traefik"
|
watch = true
|
||||||
|
prefix = "traefik"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
entryPoint = "api"
|
entryPoint = "api"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http","https"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -11,12 +10,11 @@ logLevel = "DEBUG"
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
|
|
||||||
|
[providers]
|
||||||
|
[providers.consul]
|
||||||
[consul]
|
endpoint = "{{.ConsulHost}}:8500"
|
||||||
endpoint = "{{.ConsulHost}}:8500"
|
prefix = "traefik"
|
||||||
prefix = "traefik"
|
watch = true
|
||||||
watch = true
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
entryPoint = "api"
|
entryPoint = "api"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -7,6 +7,7 @@ logLevel = "DEBUG"
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[consulCatalog]
|
[providers]
|
||||||
domain = "consul.localhost"
|
[providers.consulCatalog]
|
||||||
frontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
|
domain = "consul.localhost"
|
||||||
|
frontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -8,7 +8,8 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[docker]
|
[providers]
|
||||||
endpoint = "{{.DockerHost}}"
|
[providers.docker]
|
||||||
domain = "docker.localhost"
|
endpoint = "{{.DockerHost}}"
|
||||||
exposedByDefault = false
|
domain = "docker.localhost"
|
||||||
|
exposedByDefault = false
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -8,7 +7,8 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[docker]
|
[providers]
|
||||||
endpoint = "{{.DockerHost}}"
|
[providers.docker]
|
||||||
domain = "docker.localhost"
|
endpoint = "{{.DockerHost}}"
|
||||||
exposedByDefault = true
|
domain = "docker.localhost"
|
||||||
|
exposedByDefault = true
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -8,11 +7,12 @@ logLevel = "DEBUG"
|
||||||
[entryPoints.api]
|
[entryPoints.api]
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
|
|
||||||
[dynamodb]
|
[providers]
|
||||||
accessKeyID = "key"
|
[providers.dynamodb]
|
||||||
secretAccessKey = "secret"
|
accessKeyID = "key"
|
||||||
endpoint = "{{.DynamoURL}}"
|
secretAccessKey = "secret"
|
||||||
region = "us-east-1"
|
endpoint = "{{.DynamoURL}}"
|
||||||
|
region = "us-east-1"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
entryPoint = "api"
|
entryPoint = "api"
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8080"
|
address = ":8080"
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8080"
|
address = ":8080"
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -9,10 +8,11 @@ logLevel = "DEBUG"
|
||||||
address = ":8081"
|
address = ":8081"
|
||||||
|
|
||||||
|
|
||||||
[etcd]
|
[providers]
|
||||||
endpoint = "{{.EtcdHost}}:2379"
|
[providers.etcd]
|
||||||
prefix = "/traefik"
|
endpoint = "{{.EtcdHost}}:2379"
|
||||||
watch = true
|
prefix = "/traefik"
|
||||||
|
watch = true
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
entryPoint = "api"
|
entryPoint = "api"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http","https"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
|
[providers]
|
||||||
|
[providers.eureka]
|
||||||
|
endpoint = "http://{{.EurekaHost}}:8761/eureka"
|
||||||
|
delay = "1s"
|
||||||
|
|
||||||
[eureka]
|
|
||||||
endpoint = "http://{{.EurekaHost}}:8761/eureka"
|
|
||||||
delay = "1s"
|
|
||||||
[api]
|
[api]
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
directory = "fixtures/file/dir/"
|
[providers.file]
|
||||||
|
directory = "fixtures/file/dir/"
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
defaultEntryPoints = ["https"]
|
[serversTransport]
|
||||||
|
|
||||||
rootCAs = [ """{{ .CertContent }}""" ]
|
rootCAs = [ """{{ .CertContent }}""" ]
|
||||||
|
|
||||||
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
[[entryPoints.https.tls.certificates]]
|
[entryPoints.https.tls.DefaultCertificate]
|
||||||
certFile = """{{ .CertContent }}"""
|
certFile = """{{ .CertContent }}"""
|
||||||
keyFile = """{{ .KeyContent }}"""
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -8,7 +8,8 @@ debug = true
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
[[entryPoints.https.tls.certificates]]
|
[entryPoints.https.tls.DefaultCertificate]
|
||||||
certFile = """{{ .CertContent }}"""
|
certFile = """{{ .CertContent }}"""
|
||||||
keyFile = """{{ .KeyContent }}"""
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
|
[serversTransport]
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
|
|
||||||
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
[[entryPoints.https.tls.certificates]]
|
[entryPoints.https.tls.DefaultCertificate]
|
||||||
certFile = """{{ .CertContent }}"""
|
certFile = """{{ .CertContent }}"""
|
||||||
keyFile = """{{ .KeyContent }}"""
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
|
[serversTransport]
|
||||||
rootCAs = [ """{{ .CertContent }}""" ]
|
rootCAs = [ """{{ .CertContent }}""" ]
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
[[entryPoints.https.tls.certificates]]
|
[entryPoints.https.tls.DefaultCertificate]
|
||||||
certFile = """{{ .CertContent }}"""
|
certFile = """{{ .CertContent }}"""
|
||||||
keyFile = """{{ .KeyContent }}"""
|
keyFile = """{{ .KeyContent }}"""
|
||||||
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http1", "http2"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -10,7 +9,9 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
service = "service1"
|
service = "service1"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http1", "http2"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -10,7 +9,8 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -8,7 +7,8 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -8,7 +7,8 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[routers]
|
[routers]
|
||||||
[routers.router1]
|
[routers.router1]
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
|
@ -9,16 +8,11 @@ defaultEntryPoints = ["https"]
|
||||||
[entryPoints.https.tls.ClientCA]
|
[entryPoints.https.tls.ClientCA]
|
||||||
files = ["fixtures/https/clientca/ca1.crt"]
|
files = ["fixtures/https/clientca/ca1.crt"]
|
||||||
optional = true
|
optional = true
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "fixtures/https/snitest.com.key"
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/snitest.org.cert"
|
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
@ -41,3 +35,16 @@ defaultEntryPoints = ["https"]
|
||||||
[[Services.service2.LoadBalancer.Servers]]
|
[[Services.service2.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:9020"
|
URL = "http://127.0.0.1:9020"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.org.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,17 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
[entryPoints.https.tls.ClientCA]
|
[entryPoints.https.tls.ClientCA]
|
||||||
files = ["fixtures/https/clientca/ca1and2.crt"]
|
files = ["fixtures/https/clientca/ca1and2.crt"]
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "fixtures/https/snitest.com.key"
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/snitest.org.cert"
|
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
@ -40,3 +34,14 @@ defaultEntryPoints = ["https"]
|
||||||
[[Services.service2.LoadBalancer.Servers]]
|
[[Services.service2.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:9020"
|
URL = "http://127.0.0.1:9020"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.org.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
|
@ -9,16 +9,12 @@ defaultEntryPoints = ["https"]
|
||||||
[entryPoints.https.tls.ClientCA]
|
[entryPoints.https.tls.ClientCA]
|
||||||
files = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"]
|
files = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"]
|
||||||
optional = false
|
optional = false
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "fixtures/https/snitest.com.key"
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/snitest.org.cert"
|
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
Service = "service1"
|
Service = "service1"
|
||||||
|
@ -40,3 +36,15 @@ defaultEntryPoints = ["https"]
|
||||||
[[Services.service2.LoadBalancer.Servers]]
|
[[Services.service2.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:9020"
|
URL = "http://127.0.0.1:9020"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.org.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
|
@ -13,7 +13,7 @@ defaultEntryPoints = ["https"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
fileName = "{{.DynamicConfFileName}}"
|
fileName = "{{.DynamicConfFileName}}"
|
||||||
watch = true
|
watch = true
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
|
@ -12,7 +11,8 @@ defaultEntryPoints = ["https"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -15,7 +15,8 @@ defaultEntryPoints = ["http", "https"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/snitest.com.cert"
|
|
||||||
keyFile = "fixtures/https/snitest.com.key"
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/snitest.org.cert"
|
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
@ -38,3 +33,14 @@ defaultEntryPoints = ["https"]
|
||||||
[[Services.service2.LoadBalancer.Servers]]
|
[[Services.service2.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:9020"
|
URL = "http://127.0.0.1:9020"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.org.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
address = ":4443"
|
address = ":4443"
|
||||||
[entryPoints.https.tls]
|
[entryPoints.https.tls]
|
||||||
[entryPoints.https.tls.defaultCertificate]
|
[entryPoints.https.tls.DefaultCertificate]
|
||||||
certFile = "fixtures/https/snitest.com.cert"
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
keyFile = "fixtures/https/snitest.com.key"
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/wildcard.snitest.com.cert"
|
|
||||||
keyFile = "fixtures/https/wildcard.snitest.com.key"
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
|
||||||
certFile = "fixtures/https/www.snitest.com.cert"
|
|
||||||
keyFile = "fixtures/https/www.snitest.com.key"
|
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
@ -35,3 +30,15 @@ defaultEntryPoints = ["https"]
|
||||||
[[Services.service1.LoadBalancer.Servers]]
|
[[Services.service1.LoadBalancer.Servers]]
|
||||||
URL = "http://127.0.0.1:9010"
|
URL = "http://127.0.0.1:9010"
|
||||||
Weight = 1
|
Weight = 1
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/wildcard.snitest.com.cert"
|
||||||
|
keyFile = "fixtures/https/wildcard.snitest.com.key"
|
||||||
|
[[tls]]
|
||||||
|
entryPoints = ["https"]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/www.snitest.com.cert"
|
||||||
|
keyFile = "fixtures/https/www.snitest.com.key"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.https]
|
[entryPoints.https]
|
||||||
|
@ -13,7 +13,8 @@ defaultEntryPoints = ["https"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
|
[serversTransport]
|
||||||
# Use certificate in net/internal/testcert.go
|
# Use certificate in net/internal/testcert.go
|
||||||
rootCAs = [ """
|
rootCAs = [ """
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
|
@ -26,7 +27,8 @@ fblo6RBxUQ==
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
defaultEntryPoints = ["http"]
|
[serversTransport]
|
||||||
|
|
||||||
# Use certificate in net/internal/testcert.go
|
# Use certificate in net/internal/testcert.go
|
||||||
rootCAs = [ "fixtures/https/rootcas/local.crt"]
|
rootCAs = [ "fixtures/https/rootcas/local.crt"]
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ rootCAs = [ "fixtures/https/rootcas/local.crt"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
keepTrailingSlash = {{ .KeepTrailingSlash }}
|
keepTrailingSlash = {{ .KeepTrailingSlash }}
|
||||||
|
|
||||||
|
[log]
|
||||||
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
[providers]
|
||||||
|
[providers.file]
|
||||||
[file]
|
|
||||||
|
|
||||||
# rules
|
# rules
|
||||||
[backends]
|
[backends]
|
||||||
[backends.backend1]
|
[backends.backend1]
|
||||||
[backends.backend1.servers.server1]
|
[backends.backend1.servers.server1]
|
||||||
url = "http://172.17.0.2:80"
|
url = "http://172.17.0.2:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
[frontends]
|
[frontends]
|
||||||
[frontends.frontend1]
|
[frontends.frontend1]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
[frontends.frontend1.routes.test_1]
|
[frontends.frontend1.routes.test_1]
|
||||||
rule = "Path:/test/foo"
|
rule = "Path:/test/foo"
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
################################################################
|
################################################################
|
||||||
# Global configuration
|
# Global configuration
|
||||||
################################################################
|
################################################################
|
||||||
traefikLogsFile = "traefik.log"
|
[accessLog]
|
||||||
accessLogsFile = "access.log"
|
filePath = "access.log"
|
||||||
|
|
||||||
|
[log]
|
||||||
|
filePath = "traefik.log"
|
||||||
logLevel = "ERROR"
|
logLevel = "ERROR"
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
@ -22,7 +25,8 @@ entryPoint = "api"
|
||||||
################################################################
|
################################################################
|
||||||
# File configuration backend
|
# File configuration backend
|
||||||
################################################################
|
################################################################
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# rules
|
# rules
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -11,7 +10,8 @@ logLevel = "DEBUG"
|
||||||
[api]
|
[api]
|
||||||
entryPoint = "api"
|
entryPoint = "api"
|
||||||
|
|
||||||
[marathon]
|
[providers]
|
||||||
endpoint = "{{.MarathonURL}}"
|
[providers.marathon]
|
||||||
watch = true
|
endpoint = "{{.MarathonURL}}"
|
||||||
exposedByDefault = true
|
watch = true
|
||||||
|
exposedByDefault = true
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
[providers]
|
||||||
|
[providers.mesos]
|
||||||
[mesos]
|
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
defaultEntryPoints = ["http"]
|
[global]
|
||||||
|
|
||||||
debug=true
|
debug=true
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[docker]
|
[providers]
|
||||||
endpoint = "unix:///var/run/docker.sock"
|
[providers.docker]
|
||||||
watch = true
|
endpoint = "unix:///var/run/docker.sock"
|
||||||
exposedByDefault = false
|
watch = true
|
||||||
|
exposedByDefault = false
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[file]
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router-1]
|
[Routers.router-1]
|
||||||
Service = "service-test"
|
Service = "service-test"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -9,7 +9,8 @@ defaultEntryPoints = ["http"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -9,7 +9,9 @@ defaultEntryPoints = ["http"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
Service = "service1"
|
Service = "service1"
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":80"
|
address = ":80"
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
[entryPoints.http.transport.lifeCycle]
|
||||||
|
RequestAcceptGraceTimeout = "10s"
|
||||||
|
|
||||||
|
|
||||||
[entryPoints.traefik]
|
[entryPoints.traefik]
|
||||||
address = ":8001"
|
address = ":8001"
|
||||||
|
[entryPoints.traefik.transport.lifeCycle]
|
||||||
|
RequestAcceptGraceTimeout = "10s"
|
||||||
|
|
||||||
[lifeCycle]
|
|
||||||
requestAcceptGraceTimeout = "10s"
|
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router]
|
[Routers.router]
|
||||||
Service = "service"
|
Service = "service"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -8,7 +7,8 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
@ -17,7 +17,7 @@ logLevel = "DEBUG"
|
||||||
Rule = "PathPrefix:/"
|
Rule = "PathPrefix:/"
|
||||||
|
|
||||||
[Middlewares.retry.Retry]
|
[Middlewares.retry.Retry]
|
||||||
Attempts = 3
|
Attempts = 3
|
||||||
|
|
||||||
[Services]
|
[Services]
|
||||||
[Services.service1]
|
[Services.service1]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -12,7 +12,8 @@ defaultEntryPoints = ["http"]
|
||||||
[api]
|
[api]
|
||||||
middlewares = ["authentication"]
|
middlewares = ["authentication"]
|
||||||
|
|
||||||
[middleware.authentication.basic-auth]
|
[middlewares]
|
||||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
[middlewares.authentication.basic-auth]
|
||||||
|
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||||
|
|
||||||
[ping]
|
[ping]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -7,10 +7,11 @@ defaultEntryPoints = ["http"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[docker]
|
[providers]
|
||||||
exposedByDefault = false
|
[providers.docker]
|
||||||
domain = "docker.local"
|
exposedByDefault = false
|
||||||
watch = true
|
domain = "docker.local"
|
||||||
|
watch = true
|
||||||
|
|
||||||
[hostResolver]
|
[hostResolver]
|
||||||
cnameFlattening = true
|
cnameFlattening = true
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
[global]
|
||||||
debug=true
|
debug=true
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -6,7 +7,8 @@ debug=true
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -10,4 +10,6 @@ defaultEntryPoints = ["http"]
|
||||||
depth=2
|
depth=2
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
[docker]
|
|
||||||
|
[providers]
|
||||||
|
[providers.docker]
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
|
[serversTransport.forwardingTimeouts]
|
||||||
|
dialTimeout = "300ms"
|
||||||
|
responseHeaderTimeout = "300ms"
|
||||||
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
|
@ -10,11 +16,9 @@ defaultEntryPoints = ["http"]
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[forwardingTimeouts]
|
|
||||||
dialTimeout = "300ms"
|
|
||||||
responseHeaderTimeout = "300ms"
|
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
[log]
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
defaultEntryPoints = ["https"]
|
|
||||||
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
|
[serversTransport]
|
||||||
rootCAs = [ """{{ .RootCertContent }}""" ]
|
rootCAs = [ """{{ .RootCertContent }}""" ]
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -13,12 +17,13 @@ rootCAs = [ """{{ .RootCertContent }}""" ]
|
||||||
files = [ """{{ .RootCertContent }}""" ]
|
files = [ """{{ .RootCertContent }}""" ]
|
||||||
optional = false
|
optional = false
|
||||||
|
|
||||||
[[entryPoints.https.tls.certificates]]
|
[entryPoints.https.tls.DefaultCertificate]
|
||||||
certFile = """{{ .ServerCertContent }}"""
|
certFile = """{{ .ServerCertContent }}"""
|
||||||
keyFile = """{{ .ServerKeyContent }}"""
|
keyFile = """{{ .ServerKeyContent }}"""
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[docker]
|
[providers]
|
||||||
endpoint = "unix:///var/run/docker.sock"
|
[providers.docker]
|
||||||
watch = true
|
endpoint = "unix:///var/run/docker.sock"
|
||||||
|
watch = true
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[global]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -19,7 +20,8 @@ debug = true
|
||||||
samplingType = "const"
|
samplingType = "const"
|
||||||
samplingParam = 1.0
|
samplingParam = 1.0
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
################################################################
|
################################################################
|
||||||
# Global configuration
|
# Global configuration
|
||||||
################################################################
|
################################################################
|
||||||
[traefikLog]
|
[log]
|
||||||
filePath = "traefik.log"
|
logLevel = "DEBUG"
|
||||||
|
filePath = "traefik.log"
|
||||||
|
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
|
||||||
[accessLog]
|
[accessLog]
|
||||||
filePath = "access.log"
|
filePath = "access.log"
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
|
||||||
defaultEntryPoints = ["http"]
|
|
||||||
|
|
||||||
checkNewVersion = false
|
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
@ -19,7 +18,8 @@ checkNewVersion = false
|
||||||
[api]
|
[api]
|
||||||
dashboard = false
|
dashboard = false
|
||||||
|
|
||||||
[docker]
|
[providers]
|
||||||
exposedByDefault = false
|
[providers.docker]
|
||||||
domain = "docker.local"
|
exposedByDefault = false
|
||||||
watch = true
|
domain = "docker.local"
|
||||||
|
watch = true
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defaultEntryPoints = ["http"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
|
@ -8,7 +7,8 @@ logLevel = "DEBUG"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
defaultEntryPoints = ["wss"]
|
[log]
|
||||||
|
|
||||||
logLevel = "DEBUG"
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[serversTransport]
|
||||||
insecureSkipVerify=true
|
insecureSkipVerify=true
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.wss]
|
[entryPoints.wss]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
[entryPoints.wss.tls]
|
[entryPoints.wss.tls]
|
||||||
[[entryPoints.wss.tls.certificates]]
|
[entryPoints.wss.tls.DefaultCertificate]
|
||||||
certFile = "resources/tls/local.cert"
|
certFile = "resources/tls/local.cert"
|
||||||
keyFile = "resources/tls/local.key"
|
keyFile = "resources/tls/local.key"
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
|
||||||
[file]
|
|
||||||
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[Routers]
|
[Routers]
|
||||||
[Routers.router1]
|
[Routers.router1]
|
||||||
|
|
|
@ -61,26 +61,6 @@ func (s *SimpleSuite) TestWithWebConfig(c *check.C) {
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SimpleSuite) TestDefaultEntryPoints(c *check.C) {
|
|
||||||
cmd, output := s.cmdTraefik("--debug")
|
|
||||||
|
|
||||||
err := cmd.Start()
|
|
||||||
c.Assert(err, checker.IsNil)
|
|
||||||
defer cmd.Process.Kill()
|
|
||||||
|
|
||||||
err = try.Do(500*time.Millisecond, func() error {
|
|
||||||
expected := `\"DefaultEntryPoints\":[\"http\"]`
|
|
||||||
actual := output.String()
|
|
||||||
|
|
||||||
if !strings.Contains(actual, expected) {
|
|
||||||
return fmt.Errorf("got %s, wanted %s", actual, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
c.Assert(err, checker.IsNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SimpleSuite) TestPrintHelp(c *check.C) {
|
func (s *SimpleSuite) TestPrintHelp(c *check.C) {
|
||||||
cmd, output := s.cmdTraefik("--help")
|
cmd, output := s.cmdTraefik("--help")
|
||||||
|
|
||||||
|
@ -180,7 +160,7 @@ func (s *SimpleSuite) TestApiOnSameEntryPoint(c *check.C) {
|
||||||
s.createComposeProject(c, "base")
|
s.createComposeProject(c, "base")
|
||||||
s.composeProject.Start(c)
|
s.composeProject.Start(c)
|
||||||
|
|
||||||
cmd, output := s.traefikCmd("--defaultEntryPoints=http", "--entryPoints=Name:http Address::8000", "--api.entryPoint=http", "--debug", "--docker")
|
cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--api.entryPoint=http", "--global.debug", "--providers.docker")
|
||||||
defer output(c)
|
defer output(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -264,7 +244,7 @@ func (s *SimpleSuite) TestDefaultEntrypointHTTP(c *check.C) {
|
||||||
s.createComposeProject(c, "base")
|
s.createComposeProject(c, "base")
|
||||||
s.composeProject.Start(c)
|
s.composeProject.Start(c)
|
||||||
|
|
||||||
cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--debug", "--docker", "--api")
|
cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--global.debug", "--providers.docker", "--api")
|
||||||
defer output(c)
|
defer output(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -284,7 +264,7 @@ func (s *SimpleSuite) TestWithUnexistingEntrypoint(c *check.C) {
|
||||||
s.createComposeProject(c, "base")
|
s.createComposeProject(c, "base")
|
||||||
s.composeProject.Start(c)
|
s.composeProject.Start(c)
|
||||||
|
|
||||||
cmd, output := s.traefikCmd("--defaultEntryPoints=https,http", "--entryPoints=Name:http Address::8000", "--debug", "--docker", "--api")
|
cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--global.debug", "--providers.docker", "--api")
|
||||||
defer output(c)
|
defer output(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -304,7 +284,7 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntrypoint(c *check.C) {
|
||||||
s.createComposeProject(c, "base")
|
s.createComposeProject(c, "base")
|
||||||
s.composeProject.Start(c)
|
s.composeProject.Start(c)
|
||||||
|
|
||||||
cmd, output := s.traefikCmd("--defaultEntryPoints=http", "--entryPoints=Name:http Address::8000", "--api", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--docker", "--debug")
|
cmd, output := s.traefikCmd("--entryPoints=Name:http Address::8000", "--api", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--docker", "--global.debug")
|
||||||
defer output(c)
|
defer output(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
|
|
@ -49,7 +49,7 @@ func (s *WebsocketSuite) TestBase(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -99,7 +99,7 @@ func (s *WebsocketSuite) TestWrongOrigin(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -149,7 +149,7 @@ func (s *WebsocketSuite) TestOrigin(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -210,7 +210,7 @@ func (s *WebsocketSuite) TestWrongOriginIgnoredByServer(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -268,7 +268,7 @@ func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -331,7 +331,7 @@ func (s *WebsocketSuite) TestBasicAuth(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -375,7 +375,7 @@ func (s *WebsocketSuite) TestSpecificResponseFromBackend(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -421,7 +421,7 @@ func (s *WebsocketSuite) TestURLWithURLEncodedChar(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -476,7 +476,7 @@ func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug", "--accesslog")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug", "--accesslog")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
@ -535,7 +535,7 @@ func (s *WebsocketSuite) TestHeaderAreForwared(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd, display := s.traefikCmd(withConfigFile(file), "--debug")
|
cmd, display := s.traefikCmd(withConfigFile(file), "--global.debug")
|
||||||
defer display(c)
|
defer display(c)
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (ip *Checker) IsAuthorized(addr string) error {
|
||||||
|
|
||||||
// Contains checks if provided address is in the trusted IPs
|
// Contains checks if provided address is in the trusted IPs
|
||||||
func (ip *Checker) Contains(addr string) (bool, error) {
|
func (ip *Checker) Contains(addr string) (bool, error) {
|
||||||
if len(addr) <= 0 {
|
if len(addr) == 0 {
|
||||||
return false, errors.New("empty IP address")
|
return false, errors.New("empty IP address")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ func cnameResolve(ctx context.Context, host string, resolvPath string) (*cnameRe
|
||||||
result = append(result, tempRecord)
|
result = append(result, tempRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result) <= 0 {
|
if len(result) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,9 @@ import (
|
||||||
"github.com/containous/traefik/old/provider/rancher"
|
"github.com/containous/traefik/old/provider/rancher"
|
||||||
"github.com/containous/traefik/old/provider/rest"
|
"github.com/containous/traefik/old/provider/rest"
|
||||||
"github.com/containous/traefik/old/provider/zk"
|
"github.com/containous/traefik/old/provider/zk"
|
||||||
|
"github.com/containous/traefik/old/tls"
|
||||||
"github.com/containous/traefik/old/types"
|
"github.com/containous/traefik/old/types"
|
||||||
acmeprovider "github.com/containous/traefik/provider/acme"
|
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||||
"github.com/containous/traefik/tls"
|
|
||||||
newtypes "github.com/containous/traefik/types"
|
newtypes "github.com/containous/traefik/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
lego "github.com/xenolf/lego/acme"
|
lego "github.com/xenolf/lego/acme"
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +1,30 @@
|
||||||
package static
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
oldapi "github.com/containous/traefik/old/api"
|
"github.com/containous/traefik/config/static"
|
||||||
"github.com/containous/traefik/old/configuration"
|
"github.com/containous/traefik/old/api"
|
||||||
oldtracing "github.com/containous/traefik/old/middlewares/tracing"
|
"github.com/containous/traefik/old/middlewares/tracing"
|
||||||
oldfile "github.com/containous/traefik/old/provider/file"
|
"github.com/containous/traefik/old/provider/file"
|
||||||
oldtypes "github.com/containous/traefik/old/types"
|
"github.com/containous/traefik/old/types"
|
||||||
"github.com/containous/traefik/ping"
|
"github.com/containous/traefik/ping"
|
||||||
"github.com/containous/traefik/provider"
|
"github.com/containous/traefik/provider"
|
||||||
"github.com/containous/traefik/provider/file"
|
file2 "github.com/containous/traefik/provider/file"
|
||||||
"github.com/containous/traefik/tracing/datadog"
|
"github.com/containous/traefik/tracing/datadog"
|
||||||
"github.com/containous/traefik/tracing/jaeger"
|
"github.com/containous/traefik/tracing/jaeger"
|
||||||
"github.com/containous/traefik/tracing/zipkin"
|
"github.com/containous/traefik/tracing/zipkin"
|
||||||
"github.com/containous/traefik/types"
|
types2 "github.com/containous/traefik/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConvertStaticConf FIXME sugar
|
// ConvertStaticConf FIXME sugar
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func ConvertStaticConf(globalConfiguration configuration.GlobalConfiguration) Configuration {
|
func ConvertStaticConf(globalConfiguration GlobalConfiguration) static.Configuration {
|
||||||
staticConfiguration := Configuration{}
|
staticConfiguration := static.Configuration{}
|
||||||
|
|
||||||
staticConfiguration.EntryPoints = &EntryPoints{
|
staticConfiguration.EntryPoints = make(static.EntryPoints)
|
||||||
EntryPointList: make(EntryPointList),
|
|
||||||
Defaults: globalConfiguration.DefaultEntryPoints,
|
|
||||||
}
|
|
||||||
|
|
||||||
if globalConfiguration.EntryPoints != nil {
|
if globalConfiguration.EntryPoints != nil {
|
||||||
for name, ep := range globalConfiguration.EntryPoints {
|
for name, ep := range globalConfiguration.EntryPoints {
|
||||||
staticConfiguration.EntryPoints.EntryPointList[name] = EntryPoint{
|
staticConfiguration.EntryPoints[name] = &static.EntryPoint{
|
||||||
Address: ep.Address,
|
Address: ep.Address,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,8 +38,7 @@ func ConvertStaticConf(globalConfiguration configuration.GlobalConfiguration) Co
|
||||||
}
|
}
|
||||||
|
|
||||||
staticConfiguration.API = convertAPI(globalConfiguration.API)
|
staticConfiguration.API = convertAPI(globalConfiguration.API)
|
||||||
staticConfiguration.Constraints = convertConstraints(globalConfiguration.Constraints)
|
staticConfiguration.Providers.File = convertFile(globalConfiguration.File)
|
||||||
staticConfiguration.File = convertFile(globalConfiguration.File)
|
|
||||||
staticConfiguration.Metrics = ConvertMetrics(globalConfiguration.Metrics)
|
staticConfiguration.Metrics = ConvertMetrics(globalConfiguration.Metrics)
|
||||||
staticConfiguration.AccessLog = ConvertAccessLog(globalConfiguration.AccessLog)
|
staticConfiguration.AccessLog = ConvertAccessLog(globalConfiguration.AccessLog)
|
||||||
staticConfiguration.Tracing = ConvertTracing(globalConfiguration.Tracing)
|
staticConfiguration.Tracing = ConvertTracing(globalConfiguration.Tracing)
|
||||||
|
@ -53,35 +49,35 @@ func ConvertStaticConf(globalConfiguration configuration.GlobalConfiguration) Co
|
||||||
|
|
||||||
// ConvertAccessLog FIXME sugar
|
// ConvertAccessLog FIXME sugar
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func ConvertAccessLog(old *oldtypes.AccessLog) *types.AccessLog {
|
func ConvertAccessLog(old *types.AccessLog) *types2.AccessLog {
|
||||||
if old == nil {
|
if old == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
accessLog := &types.AccessLog{
|
accessLog := &types2.AccessLog{
|
||||||
FilePath: old.FilePath,
|
FilePath: old.FilePath,
|
||||||
Format: old.Format,
|
Format: old.Format,
|
||||||
BufferingSize: old.BufferingSize,
|
BufferingSize: old.BufferingSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
if old.Filters != nil {
|
if old.Filters != nil {
|
||||||
accessLog.Filters = &types.AccessLogFilters{
|
accessLog.Filters = &types2.AccessLogFilters{
|
||||||
StatusCodes: types.StatusCodes(old.Filters.StatusCodes),
|
StatusCodes: types2.StatusCodes(old.Filters.StatusCodes),
|
||||||
RetryAttempts: old.Filters.RetryAttempts,
|
RetryAttempts: old.Filters.RetryAttempts,
|
||||||
MinDuration: old.Filters.MinDuration,
|
MinDuration: old.Filters.MinDuration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if old.Fields != nil {
|
if old.Fields != nil {
|
||||||
accessLog.Fields = &types.AccessLogFields{
|
accessLog.Fields = &types2.AccessLogFields{
|
||||||
DefaultMode: old.Fields.DefaultMode,
|
DefaultMode: old.Fields.DefaultMode,
|
||||||
Names: types.FieldNames(old.Fields.Names),
|
Names: types2.FieldNames(old.Fields.Names),
|
||||||
}
|
}
|
||||||
|
|
||||||
if old.Fields.Headers != nil {
|
if old.Fields.Headers != nil {
|
||||||
accessLog.Fields.Headers = &types.FieldHeaders{
|
accessLog.Fields.Headers = &types2.FieldHeaders{
|
||||||
DefaultMode: old.Fields.Headers.DefaultMode,
|
DefaultMode: old.Fields.Headers.DefaultMode,
|
||||||
Names: types.FieldHeaderNames(old.Fields.Headers.Names),
|
Names: types2.FieldHeaderNames(old.Fields.Headers.Names),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,35 +87,35 @@ func ConvertAccessLog(old *oldtypes.AccessLog) *types.AccessLog {
|
||||||
|
|
||||||
// ConvertMetrics FIXME sugar
|
// ConvertMetrics FIXME sugar
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func ConvertMetrics(old *oldtypes.Metrics) *types.Metrics {
|
func ConvertMetrics(old *types.Metrics) *types2.Metrics {
|
||||||
if old == nil {
|
if old == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics := &types.Metrics{}
|
metrics := &types2.Metrics{}
|
||||||
|
|
||||||
if old.Prometheus != nil {
|
if old.Prometheus != nil {
|
||||||
metrics.Prometheus = &types.Prometheus{
|
metrics.Prometheus = &types2.Prometheus{
|
||||||
EntryPoint: old.Prometheus.EntryPoint,
|
EntryPoint: old.Prometheus.EntryPoint,
|
||||||
Buckets: types.Buckets(old.Prometheus.Buckets),
|
Buckets: types2.Buckets(old.Prometheus.Buckets),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if old.Datadog != nil {
|
if old.Datadog != nil {
|
||||||
metrics.Datadog = &types.Datadog{
|
metrics.Datadog = &types2.Datadog{
|
||||||
Address: old.Datadog.Address,
|
Address: old.Datadog.Address,
|
||||||
PushInterval: old.Datadog.PushInterval,
|
PushInterval: old.Datadog.PushInterval,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if old.StatsD != nil {
|
if old.StatsD != nil {
|
||||||
metrics.StatsD = &types.Statsd{
|
metrics.StatsD = &types2.Statsd{
|
||||||
Address: old.StatsD.Address,
|
Address: old.StatsD.Address,
|
||||||
PushInterval: old.StatsD.PushInterval,
|
PushInterval: old.StatsD.PushInterval,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if old.InfluxDB != nil {
|
if old.InfluxDB != nil {
|
||||||
metrics.InfluxDB = &types.InfluxDB{
|
metrics.InfluxDB = &types2.InfluxDB{
|
||||||
Address: old.InfluxDB.Address,
|
Address: old.InfluxDB.Address,
|
||||||
Protocol: old.InfluxDB.Protocol,
|
Protocol: old.InfluxDB.Protocol,
|
||||||
PushInterval: old.InfluxDB.PushInterval,
|
PushInterval: old.InfluxDB.PushInterval,
|
||||||
|
@ -135,12 +131,12 @@ func ConvertMetrics(old *oldtypes.Metrics) *types.Metrics {
|
||||||
|
|
||||||
// ConvertTracing FIXME sugar
|
// ConvertTracing FIXME sugar
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func ConvertTracing(old *oldtracing.Tracing) *Tracing {
|
func ConvertTracing(old *tracing.Tracing) *static.Tracing {
|
||||||
if old == nil {
|
if old == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tra := &Tracing{
|
tra := &static.Tracing{
|
||||||
Backend: old.Backend,
|
Backend: old.Backend,
|
||||||
ServiceName: old.ServiceName,
|
ServiceName: old.ServiceName,
|
||||||
SpanNameLimit: old.SpanNameLimit,
|
SpanNameLimit: old.SpanNameLimit,
|
||||||
|
@ -177,19 +173,19 @@ func ConvertTracing(old *oldtracing.Tracing) *Tracing {
|
||||||
return tra
|
return tra
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertAPI(old *oldapi.Handler) *API {
|
func convertAPI(old *api.Handler) *static.API {
|
||||||
if old == nil {
|
if old == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
api := &API{
|
api := &static.API{
|
||||||
EntryPoint: old.EntryPoint,
|
EntryPoint: old.EntryPoint,
|
||||||
Dashboard: old.Dashboard,
|
Dashboard: old.Dashboard,
|
||||||
DashboardAssets: old.DashboardAssets,
|
DashboardAssets: old.DashboardAssets,
|
||||||
}
|
}
|
||||||
|
|
||||||
if old.Statistics != nil {
|
if old.Statistics != nil {
|
||||||
api.Statistics = &types.Statistics{
|
api.Statistics = &types2.Statistics{
|
||||||
RecentErrors: old.Statistics.RecentErrors,
|
RecentErrors: old.Statistics.RecentErrors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,10 +193,10 @@ func convertAPI(old *oldapi.Handler) *API {
|
||||||
return api
|
return api
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertConstraints(oldConstraints oldtypes.Constraints) types.Constraints {
|
func convertConstraints(oldConstraints types.Constraints) types2.Constraints {
|
||||||
constraints := types.Constraints{}
|
constraints := types2.Constraints{}
|
||||||
for _, value := range oldConstraints {
|
for _, value := range oldConstraints {
|
||||||
constraint := &types.Constraint{
|
constraint := &types2.Constraint{
|
||||||
Key: value.Key,
|
Key: value.Key,
|
||||||
MustMatch: value.MustMatch,
|
MustMatch: value.MustMatch,
|
||||||
Regex: value.Regex,
|
Regex: value.Regex,
|
||||||
|
@ -211,12 +207,12 @@ func convertConstraints(oldConstraints oldtypes.Constraints) types.Constraints {
|
||||||
return constraints
|
return constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertFile(old *oldfile.Provider) *file.Provider {
|
func convertFile(old *file.Provider) *file2.Provider {
|
||||||
if old == nil {
|
if old == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f := &file.Provider{
|
f := &file2.Provider{
|
||||||
BaseProvider: provider.BaseProvider{
|
BaseProvider: provider.BaseProvider{
|
||||||
Watch: old.Watch,
|
Watch: old.Watch,
|
||||||
Filename: old.Filename,
|
Filename: old.Filename,
|
||||||
|
@ -233,12 +229,12 @@ func convertFile(old *oldfile.Provider) *file.Provider {
|
||||||
|
|
||||||
// ConvertHostResolverConfig FIXME
|
// ConvertHostResolverConfig FIXME
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func ConvertHostResolverConfig(oldconfig *configuration.HostResolverConfig) *HostResolverConfig {
|
func ConvertHostResolverConfig(oldconfig *HostResolverConfig) *static.HostResolverConfig {
|
||||||
if oldconfig == nil {
|
if oldconfig == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &HostResolverConfig{
|
return &static.HostResolverConfig{
|
||||||
CnameFlattening: oldconfig.CnameFlattening,
|
CnameFlattening: oldconfig.CnameFlattening,
|
||||||
ResolvConfig: oldconfig.ResolvConfig,
|
ResolvConfig: oldconfig.ResolvConfig,
|
||||||
ResolvDepth: oldconfig.ResolvDepth,
|
ResolvDepth: oldconfig.ResolvDepth,
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containous/traefik/old/log"
|
"github.com/containous/traefik/old/log"
|
||||||
|
"github.com/containous/traefik/old/tls"
|
||||||
"github.com/containous/traefik/old/types"
|
"github.com/containous/traefik/old/types"
|
||||||
"github.com/containous/traefik/tls"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// EntryPoint holds an entry point configuration of the reverse proxy (ip, port, TLS...)
|
// EntryPoint holds an entry point configuration of the reverse proxy (ip, port, TLS...)
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
244
old/tls/certificate.go
Normal 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"
|
||||||
|
}
|
137
old/tls/certificate_store.go
Normal file
137
old/tls/certificate_store.go
Normal 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
|
||||||
|
}
|
94
old/tls/generate/generate.go
Normal file
94
old/tls/generate/generate.go
Normal 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
101
old/tls/tls.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -124,7 +124,7 @@ func (p *Provider) ListenRequest(domain string) (*tls.Certificate, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init for compatibility reason the BaseProvider implements an empty Init
|
// Init for compatibility reason the BaseProvider implements an empty Init
|
||||||
func (p *Provider) Init(_ types.Constraints) error {
|
func (p *Provider) Init() error {
|
||||||
ctx := log.With(context.Background(), log.Str(log.ProviderName, "acme"))
|
ctx := log.With(context.Background(), log.Str(log.ProviderName, "acme"))
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,10 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
||||||
domainSafe := &safe.Safe{}
|
domainSafe := &safe.Safe{}
|
||||||
domainSafe.Set(domainMap)
|
domainSafe.Set(domainMap)
|
||||||
|
|
||||||
|
// FIXME Add a test for DefaultCertificate
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
dynamicCerts *safe.Safe
|
dynamicCerts *safe.Safe
|
||||||
staticCerts *safe.Safe
|
|
||||||
resolvingDomains map[string]struct{}
|
resolvingDomains map[string]struct{}
|
||||||
acmeCertificates []*Certificate
|
acmeCertificates []*Certificate
|
||||||
domains []string
|
domains []string
|
||||||
|
@ -45,12 +45,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
||||||
dynamicCerts: wildcardSafe,
|
dynamicCerts: wildcardSafe,
|
||||||
expectedDomains: nil,
|
expectedDomains: nil,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
desc: "wildcard already exists in static certificates",
|
|
||||||
domains: []string{"*.traefik.wtf"},
|
|
||||||
staticCerts: wildcardSafe,
|
|
||||||
expectedDomains: nil,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
desc: "wildcard already exists in ACME certificates",
|
desc: "wildcard already exists in ACME certificates",
|
||||||
domains: []string{"*.traefik.wtf"},
|
domains: []string{"*.traefik.wtf"},
|
||||||
|
@ -72,12 +66,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
||||||
dynamicCerts: domainSafe,
|
dynamicCerts: domainSafe,
|
||||||
expectedDomains: []string{"foo.traefik.wtf"},
|
expectedDomains: []string{"foo.traefik.wtf"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
desc: "domain CN already exists in static certificates and SANs to generate",
|
|
||||||
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
|
|
||||||
staticCerts: domainSafe,
|
|
||||||
expectedDomains: []string{"foo.traefik.wtf"},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
desc: "domain CN already exists in ACME certificates and SANs to generate",
|
desc: "domain CN already exists in ACME certificates and SANs to generate",
|
||||||
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
|
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
|
||||||
|
@ -94,12 +82,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
||||||
dynamicCerts: domainSafe,
|
dynamicCerts: domainSafe,
|
||||||
expectedDomains: nil,
|
expectedDomains: nil,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
desc: "domain already exists in static certificates",
|
|
||||||
domains: []string{"traefik.wtf"},
|
|
||||||
staticCerts: domainSafe,
|
|
||||||
expectedDomains: nil,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
desc: "domain already exists in ACME certificates",
|
desc: "domain already exists in ACME certificates",
|
||||||
domains: []string{"traefik.wtf"},
|
domains: []string{"traefik.wtf"},
|
||||||
|
@ -116,12 +98,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
||||||
dynamicCerts: wildcardSafe,
|
dynamicCerts: wildcardSafe,
|
||||||
expectedDomains: nil,
|
expectedDomains: nil,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
desc: "domain matched by wildcard in static certificates",
|
|
||||||
domains: []string{"who.traefik.wtf", "foo.traefik.wtf"},
|
|
||||||
staticCerts: wildcardSafe,
|
|
||||||
expectedDomains: nil,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
desc: "domain matched by wildcard in ACME certificates",
|
desc: "domain matched by wildcard in ACME certificates",
|
||||||
domains: []string{"who.traefik.wtf", "foo.traefik.wtf"},
|
domains: []string{"who.traefik.wtf", "foo.traefik.wtf"},
|
||||||
|
@ -190,7 +166,6 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
||||||
acmeProvider := Provider{
|
acmeProvider := Provider{
|
||||||
certificateStore: &traefiktls.CertificateStore{
|
certificateStore: &traefiktls.CertificateStore{
|
||||||
DynamicCerts: test.dynamicCerts,
|
DynamicCerts: test.dynamicCerts,
|
||||||
StaticCerts: test.staticCerts,
|
|
||||||
},
|
},
|
||||||
certificates: test.acmeCertificates,
|
certificates: test.acmeCertificates,
|
||||||
resolvingDomains: test.resolvingDomains,
|
resolvingDomains: test.resolvingDomains,
|
||||||
|
|
|
@ -8,20 +8,16 @@ import (
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/provider"
|
"github.com/containous/traefik/provider"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProviderAggregator aggregates providers.
|
// ProviderAggregator aggregates providers.
|
||||||
type ProviderAggregator struct {
|
type ProviderAggregator struct {
|
||||||
providers []provider.Provider
|
providers []provider.Provider
|
||||||
constraints types.Constraints
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProviderAggregator returns an aggregate of all the providers configured in the static configuration.
|
// NewProviderAggregator returns an aggregate of all the providers configured in the static configuration.
|
||||||
func NewProviderAggregator(conf static.Configuration) ProviderAggregator {
|
func NewProviderAggregator(conf static.Providers) ProviderAggregator {
|
||||||
p := ProviderAggregator{
|
p := ProviderAggregator{}
|
||||||
constraints: conf.Constraints,
|
|
||||||
}
|
|
||||||
|
|
||||||
if conf.File != nil {
|
if conf.File != nil {
|
||||||
p.quietAddProvider(conf.File)
|
p.quietAddProvider(conf.File)
|
||||||
|
@ -39,7 +35,7 @@ func (p *ProviderAggregator) quietAddProvider(provider provider.Provider) {
|
||||||
|
|
||||||
// AddProvider adds a provider in the providers map.
|
// AddProvider adds a provider in the providers map.
|
||||||
func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
|
func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
|
||||||
err := provider.Init(p.constraints)
|
err := provider.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -48,7 +44,7 @@ func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init the provider
|
// Init the provider
|
||||||
func (p ProviderAggregator) Init(_ types.Constraints) error {
|
func (p ProviderAggregator) Init() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,7 @@ type BaseProvider struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init for compatibility reason the BaseProvider implements an empty Init.
|
// Init for compatibility reason the BaseProvider implements an empty Init.
|
||||||
func (p *BaseProvider) Init(constraints types.Constraints) error {
|
func (p *BaseProvider) Init() error {
|
||||||
p.Constraints = append(p.Constraints, constraints...)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"github.com/containous/traefik/provider"
|
"github.com/containous/traefik/provider"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/tls"
|
"github.com/containous/traefik/tls"
|
||||||
"github.com/containous/traefik/types"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/fsnotify.v1"
|
"gopkg.in/fsnotify.v1"
|
||||||
)
|
)
|
||||||
|
@ -32,8 +31,8 @@ type Provider struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init the provider
|
// Init the provider
|
||||||
func (p *Provider) Init(constraints types.Constraints) error {
|
func (p *Provider) Init() error {
|
||||||
return p.BaseProvider.Init(constraints)
|
return p.BaseProvider.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide allows the file provider to provide configurations to traefik
|
// Provide allows the file provider to provide configurations to traefik
|
||||||
|
|
|
@ -3,7 +3,6 @@ package provider
|
||||||
import (
|
import (
|
||||||
"github.com/containous/traefik/config"
|
"github.com/containous/traefik/config"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider defines methods of a provider.
|
// Provider defines methods of a provider.
|
||||||
|
@ -11,5 +10,5 @@ type Provider interface {
|
||||||
// Provide allows the provider to provide configurations to traefik
|
// Provide allows the provider to provide configurations to traefik
|
||||||
// using the given configuration channel.
|
// using the given configuration channel.
|
||||||
Provide(configurationChan chan<- config.Message, pool *safe.Pool) error
|
Provide(configurationChan chan<- config.Message, pool *safe.Pool) error
|
||||||
Init(constraints types.Constraints) error
|
Init() error
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue