Dynamic Configuration Refactoring

This commit is contained in:
Ludovic Fernandez 2018-11-14 10:18:03 +01:00 committed by Traefiker Bot
parent d3ae88f108
commit a09dfa3ce1
452 changed files with 21023 additions and 9419 deletions

View file

@ -1,3 +1,10 @@
[run]
deadline = "5m"
skip-files = [
"^old/.*",
]
[linters-settings]
[linters-settings.govet]
@ -13,8 +20,8 @@
suggest-new = true
[linters-settings.goconst]
min-len = 2.0
min-occurrences = 2.0
min-len = 3.0
min-occurrences = 3.0
[linters-settings.misspell]
locale = "US"
@ -22,9 +29,19 @@
[linters]
enable-all = true
disable = [
"maligned",
"lll",
"gas",
"dupl",
"prealloc"
"maligned",
"lll",
"gas",
"dupl",
"prealloc",
]
[issues]
max-per-linter = 0
max-same = 0
exclude = [
"(.+) is deprecated:",
"cyclomatic complexity (\\d+) of func `\\(\\*Builder\\)\\.buildConstructor` is high", #alt/server/middleware/middlewares.go
"`logger` can be `github.com/containous/traefik/vendor/github.com/stretchr/testify/assert.TestingT`", # alt/middlewares/recovery/recovery.go:
"`fn` can be `net/http.Handler`", # alt/server/alice/chain.go
]

37
Gopkg.lock generated
View file

@ -7,12 +7,6 @@
revision = "056a55f54a6cc77b440b31a56a5e7c3982d32811"
version = "v0.22.0"
[[projects]]
branch = "master"
name = "code.cloudfoundry.org/clock"
packages = ["."]
revision = "02e53af36e6c978af692887ed449b74026d76fec"
[[projects]]
branch = "master"
name = "github.com/ArthurHlt/go-eureka-client"
@ -87,11 +81,6 @@
packages = ["."]
revision = "e039e20e500c2c025d9145be375e27cf42a94174"
[[projects]]
name = "github.com/Microsoft/ApplicationInsights-Go"
packages = ["appinsights"]
revision = "98ac7ca026c26818888600ea0d966987aa56f043"
[[projects]]
name = "github.com/Microsoft/go-winio"
packages = ["."]
@ -277,6 +266,12 @@
packages = ["pathdriver"]
revision = "b2b946a77f5973f420514090d6f6dd58b08303f0"
[[projects]]
branch = "containous-fork"
name = "github.com/containous/alice"
packages = ["."]
revision = "d83ebdd94cbdbcd9c6c6a22e1a0cde05e55d9d90"
[[projects]]
name = "github.com/containous/flaeg"
packages = [
@ -298,12 +293,6 @@
revision = "66717a0e0ca950c4b6dc8c87b46da0b8495c6e41"
version = "v3.1.1"
[[projects]]
name = "github.com/containous/traefik-extra-service-fabric"
packages = ["."]
revision = "6e90a9eef2ac9d320e55d6e994d169673a8d8b0f"
version = "v1.3.0"
[[projects]]
name = "github.com/coreos/bbolt"
packages = ["."]
@ -801,18 +790,6 @@
revision = "2d474a3089bcfce6b472779be9470a1f0ef3d5e4"
version = "v1.3.7"
[[projects]]
branch = "master"
name = "github.com/jjcollinge/logrus-appinsights"
packages = ["."]
revision = "9b66602d496a139e4722bdde32f0f1ac1c12d4a8"
[[projects]]
branch = "master"
name = "github.com/jjcollinge/servicefabric"
packages = ["."]
revision = "8eebe170fa1ba25d3dfb928b3f86a7313b13b9fe"
[[projects]]
name = "github.com/jmespath/go-jmespath"
packages = ["."]
@ -1814,6 +1791,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "37e89a543fca153d166cc70fd7fed689f06d894140bf617f69f5f664ffee621e"
inputs-digest = "d4f73c986b64003e14a36894149943e956e0dfa40b8837bfd11bf5fa3ad78c77"
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -19,6 +19,11 @@
# name = "github.com/x/y"
# version = "2.4.0"
[prune]
non-go = true
go-tests = true
unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/ArthurHlt/go-eureka-client"
@ -60,13 +65,17 @@
branch = "master"
name = "github.com/containous/mux"
[[constraint]]
branch = "containous-fork"
name = "github.com/containous/alice"
[[constraint]]
name = "github.com/containous/staert"
version = "3.1.1"
[[constraint]]
name = "github.com/containous/traefik-extra-service-fabric"
version = "1.3.0"
#[[constraint]]
# name = "github.com/containous/traefik-extra-service-fabric"
# version = "1.3.0"
[[constraint]]
name = "github.com/coreos/go-systemd"
@ -111,9 +120,9 @@
name = "github.com/influxdata/influxdb"
version = "1.3.7"
[[constraint]]
branch = "master"
name = "github.com/jjcollinge/servicefabric"
#[[constraint]]
# branch = "master"
# name = "github.com/jjcollinge/servicefabric"
[[constraint]]
branch = "master"
@ -252,11 +261,6 @@
branch = "master"
name = "github.com/miekg/dns"
[prune]
non-go = true
go-tests = true
unused-packages = true
[[constraint]]
name = "github.com/patrickmn/go-cache"
version = "2.1.0"

View file

@ -15,8 +15,8 @@ import (
"time"
"github.com/containous/traefik/log"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/types"
acmeprovider "github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/types"
"github.com/xenolf/lego/acme"
)

View file

@ -22,12 +22,11 @@ import (
"github.com/containous/staert"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/log"
acmeprovider "github.com/containous/traefik/provider/acme"
acmeprovider "github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/eapache/channels"
"github.com/sirupsen/logrus"
"github.com/xenolf/lego/acme"
legolog "github.com/xenolf/lego/log"
"github.com/xenolf/lego/providers/dns"
@ -53,8 +52,6 @@ type ACME struct {
DNSChallenge *acmeprovider.DNSChallenge `description:"Activate DNS-01 Challenge"`
HTTPChallenge *acmeprovider.HTTPChallenge `description:"Activate HTTP-01 Challenge"`
TLSChallenge *acmeprovider.TLSChallenge `description:"Activate TLS-ALPN-01 Challenge"`
DNSProvider string `description:"(Deprecated) Activate DNS-01 Challenge"` // Deprecated
DelayDontCheckDNS flaeg.Duration `description:"(Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."` // Deprecated
ACMELogging bool `description:"Enable debug logging of ACME actions."`
OverrideCertificates bool `description:"Enable to override certificates in key-value store when using storeconfig"`
client *acme.Client
@ -73,7 +70,7 @@ func (a *ACME) init() error {
acme.UserAgent = fmt.Sprintf("containous-traefik/%s", version.Version)
if a.ACMELogging {
legolog.Logger = fmtlog.New(log.WriterLevel(logrus.InfoLevel), "legolog: ", 0)
legolog.Logger = log.WithoutContext()
} else {
legolog.Logger = fmtlog.New(ioutil.Discard, "", 0)
}
@ -744,7 +741,7 @@ func (a *ACME) getValidDomains(domains []string, wildcardAllowed bool) ([]string
return nil, fmt.Errorf("unable to generate a wildcard certificate for domain %q from a 'Host' rule", strings.Join(domains, ","))
}
if a.DNSChallenge == nil && len(a.DNSProvider) == 0 {
if a.DNSChallenge == nil {
return nil, fmt.Errorf("unable to generate a wildcard certificate for domain %q : ACME needs a DNSChallenge", strings.Join(domains, ","))
}
if strings.HasPrefix(domains[0], "*.*") {

View file

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

View file

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

View file

@ -8,29 +8,29 @@ import (
"github.com/containous/flaeg/parse"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/api"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/middlewares"
"github.com/containous/traefik/provider"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/provider/boltdb"
"github.com/containous/traefik/provider/consul"
"github.com/containous/traefik/provider/consulcatalog"
"github.com/containous/traefik/provider/docker"
"github.com/containous/traefik/provider/dynamodb"
"github.com/containous/traefik/provider/ecs"
"github.com/containous/traefik/provider/etcd"
"github.com/containous/traefik/provider/eureka"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/provider/kubernetes"
"github.com/containous/traefik/provider/kv"
"github.com/containous/traefik/provider/marathon"
"github.com/containous/traefik/provider/mesos"
"github.com/containous/traefik/provider/rancher"
"github.com/containous/traefik/provider/zk"
"github.com/containous/traefik/old/api"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/middlewares"
"github.com/containous/traefik/old/provider"
acmeprovider "github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/provider/boltdb"
"github.com/containous/traefik/old/provider/consul"
"github.com/containous/traefik/old/provider/consulcatalog"
"github.com/containous/traefik/old/provider/docker"
"github.com/containous/traefik/old/provider/dynamodb"
"github.com/containous/traefik/old/provider/ecs"
"github.com/containous/traefik/old/provider/etcd"
"github.com/containous/traefik/old/provider/eureka"
"github.com/containous/traefik/old/provider/file"
"github.com/containous/traefik/old/provider/kubernetes"
"github.com/containous/traefik/old/provider/kv"
"github.com/containous/traefik/old/provider/marathon"
"github.com/containous/traefik/old/provider/mesos"
"github.com/containous/traefik/old/provider/rancher"
"github.com/containous/traefik/old/provider/zk"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/safe"
traefiktls "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/elazarl/go-bindata-assetfs"
"github.com/thoas/stats"
)
@ -173,15 +173,14 @@ func TestDo_globalConfiguration(t *testing.T) {
SANs: []string{"Domains acme SANs 1", "Domains acme SANs 2", "Domains acme SANs 3"},
},
},
Storage: "Storage",
StorageFile: "StorageFile",
OnDemand: true,
OnHostRule: true,
CAServer: "CAServer",
EntryPoint: "EntryPoint",
DNSChallenge: &acmeprovider.DNSChallenge{Provider: "DNSProvider"},
DelayDontCheckDNS: 666,
ACMELogging: true,
Storage: "Storage",
StorageFile: "StorageFile",
OnDemand: true,
OnHostRule: true,
CAServer: "CAServer",
EntryPoint: "EntryPoint",
DNSChallenge: &acmeprovider.DNSChallenge{Provider: "DNSProvider"},
ACMELogging: true,
TLSConfig: &tls.Config{
InsecureSkipVerify: true,
// ...

View file

@ -13,10 +13,10 @@ type DashboardHandler struct {
Assets *assetfs.AssetFS
}
// AddRoutes add dashboard routes on a router
func (g DashboardHandler) AddRoutes(router *mux.Router) {
// Append add dashboard routes on a router
func (g DashboardHandler) Append(router *mux.Router) {
if g.Assets == nil {
log.Error("No assets for dashboard")
log.WithoutContext().Error("No assets for dashboard")
return
}

View file

@ -11,7 +11,8 @@ import (
)
func init() {
expvar.Publish("Goroutines", expvar.Func(goroutines))
// FIXME Goroutines2 -> Goroutines
expvar.Publish("Goroutines2", expvar.Func(goroutines))
}
func goroutines() interface{} {
@ -21,8 +22,8 @@ func goroutines() interface{} {
// DebugHandler expose debug routes
type DebugHandler struct{}
// AddRoutes add debug routes on a router
func (g DebugHandler) AddRoutes(router *mux.Router) {
// Append add debug routes on a router
func (g DebugHandler) Append(router *mux.Router) {
router.Methods(http.MethodGet).Path("/debug/vars").
HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")

View file

@ -1,252 +1,304 @@
package api
import (
"io"
"net/http"
"github.com/containous/mux"
"github.com/containous/traefik/config"
"github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/elazarl/go-bindata-assetfs"
thoas_stats "github.com/thoas/stats"
thoasstats "github.com/thoas/stats"
"github.com/unrolled/render"
)
// ResourceIdentifier a resource identifier
type ResourceIdentifier struct {
ID string `json:"id"`
Path string `json:"path"`
}
// ProviderRepresentation a provider with resource identifiers
type ProviderRepresentation struct {
Routers []ResourceIdentifier `json:"routers,omitempty"`
Middlewares []ResourceIdentifier `json:"middlewares,omitempty"`
Services []ResourceIdentifier `json:"services,omitempty"`
}
// RouterRepresentation extended version of a router configuration with an ID
type RouterRepresentation struct {
*config.Router
ID string `json:"id"`
}
// MiddlewareRepresentation extended version of a middleware configuration with an ID
type MiddlewareRepresentation struct {
*config.Middleware
ID string `json:"id"`
}
// ServiceRepresentation extended version of a service configuration with an ID
type ServiceRepresentation struct {
*config.Service
ID string `json:"id"`
}
// Handler expose api routes
type Handler struct {
EntryPoint string `description:"EntryPoint" export:"true"`
Dashboard bool `description:"Activate dashboard" export:"true"`
Debug bool `export:"true"`
EntryPoint string
Dashboard bool
Debug bool
CurrentConfigurations *safe.Safe
Statistics *types.Statistics `description:"Enable more detailed statistics" export:"true"`
Stats *thoas_stats.Stats `json:"-"`
StatsRecorder *middlewares.StatsRecorder `json:"-"`
DashboardAssets *assetfs.AssetFS `json:"-"`
Statistics *types.Statistics
Stats *thoasstats.Stats
// StatsRecorder *middlewares.StatsRecorder // FIXME stats
DashboardAssets *assetfs.AssetFS
}
var (
templatesRenderer = render.New(render.Options{
Directory: "nowhere",
})
)
var templateRenderer jsonRenderer = render.New(render.Options{Directory: "nowhere"})
// AddRoutes add api routes on a router
func (p Handler) AddRoutes(router *mux.Router) {
type jsonRenderer interface {
JSON(w io.Writer, status int, v interface{}) error
}
// Append add api routes on a router
func (p Handler) Append(router *mux.Router) {
if p.Debug {
DebugHandler{}.AddRoutes(router)
DebugHandler{}.Append(router)
}
router.Methods(http.MethodGet).Path("/api").HandlerFunc(p.getConfigHandler)
router.Methods(http.MethodGet).Path("/api/providers").HandlerFunc(p.getConfigHandler)
router.Methods(http.MethodGet).Path("/api/providers").HandlerFunc(p.getProvidersHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}").HandlerFunc(p.getProviderHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/backends").HandlerFunc(p.getBackendsHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/backends/{backend}").HandlerFunc(p.getBackendHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/backends/{backend}/servers").HandlerFunc(p.getServersHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/backends/{backend}/servers/{server}").HandlerFunc(p.getServerHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/frontends").HandlerFunc(p.getFrontendsHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/frontends/{frontend}").HandlerFunc(p.getFrontendHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/frontends/{frontend}/routes").HandlerFunc(p.getRoutesHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/frontends/{frontend}/routes/{route}").HandlerFunc(p.getRouteHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/routers").HandlerFunc(p.getRoutersHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/routers/{router}").HandlerFunc(p.getRouterHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/middlewares").HandlerFunc(p.getMiddlewaresHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/middlewares/{middleware}").HandlerFunc(p.getMiddlewareHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/services").HandlerFunc(p.getServicesHandler)
router.Methods(http.MethodGet).Path("/api/providers/{provider}/services/{service}").HandlerFunc(p.getServiceHandler)
// FIXME stats
// health route
router.Methods(http.MethodGet).Path("/health").HandlerFunc(p.getHealthHandler)
//router.Methods(http.MethodGet).Path("/health").HandlerFunc(p.getHealthHandler)
version.Handler{}.AddRoutes(router)
version.Handler{}.Append(router)
if p.Dashboard {
DashboardHandler{Assets: p.DashboardAssets}.AddRoutes(router)
DashboardHandler{Assets: p.DashboardAssets}.Append(router)
}
}
func getProviderIDFromVars(vars map[string]string) string {
providerID := vars["provider"]
// TODO: Deprecated
if providerID == "rest" {
providerID = "web"
func (p Handler) getProvidersHandler(rw http.ResponseWriter, request *http.Request) {
// FIXME handle currentConfiguration
if p.CurrentConfigurations != nil {
currentConfigurations, ok := p.CurrentConfigurations.Get().(config.Configurations)
if !ok {
rw.WriteHeader(http.StatusOK)
return
}
var providers []ResourceIdentifier
for name := range currentConfigurations {
providers = append(providers, ResourceIdentifier{
ID: name,
Path: "/api/providers/" + name,
})
}
err := templateRenderer.JSON(rw, http.StatusOK, providers)
if err != nil {
log.FromContext(request.Context()).Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
return providerID
}
func (p Handler) getConfigHandler(response http.ResponseWriter, request *http.Request) {
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
err := templatesRenderer.JSON(response, http.StatusOK, currentConfigurations)
func (p Handler) getProviderHandler(rw http.ResponseWriter, request *http.Request) {
providerID := mux.Vars(request)["provider"]
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
provider, ok := currentConfigurations[providerID]
if !ok {
http.NotFound(rw, request)
return
}
var routers []ResourceIdentifier
for name := range provider.Routers {
routers = append(routers, ResourceIdentifier{
ID: name,
Path: "/api/providers/" + providerID + "/routers",
})
}
var services []ResourceIdentifier
for name := range provider.Services {
services = append(services, ResourceIdentifier{
ID: name,
Path: "/api/providers/" + providerID + "/services",
})
}
var middlewares []ResourceIdentifier
for name := range provider.Middlewares {
middlewares = append(middlewares, ResourceIdentifier{
ID: name,
Path: "/api/providers/" + providerID + "/middlewares",
})
}
providers := ProviderRepresentation{Routers: routers, Middlewares: middlewares, Services: services}
err := templateRenderer.JSON(rw, http.StatusOK, providers)
if err != nil {
log.Error(err)
log.FromContext(request.Context()).Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
func (p Handler) getProviderHandler(response http.ResponseWriter, request *http.Request) {
providerID := getProviderIDFromVars(mux.Vars(request))
func (p Handler) getRoutersHandler(rw http.ResponseWriter, request *http.Request) {
providerID := mux.Vars(request)["provider"]
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, provider)
if err != nil {
log.Error(err)
}
} else {
http.NotFound(response, request)
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
provider, ok := currentConfigurations[providerID]
if !ok {
http.NotFound(rw, request)
return
}
}
func (p Handler) getBackendsHandler(response http.ResponseWriter, request *http.Request) {
providerID := getProviderIDFromVars(mux.Vars(request))
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, provider.Backends)
if err != nil {
log.Error(err)
}
} else {
http.NotFound(response, request)
var routers []RouterRepresentation
for name, router := range provider.Routers {
routers = append(routers, RouterRepresentation{Router: router, ID: name})
}
}
func (p Handler) getBackendHandler(response http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
providerID := getProviderIDFromVars(vars)
backendID := vars["backend"]
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
if backend, ok := provider.Backends[backendID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, backend)
if err != nil {
log.Error(err)
}
return
}
}
http.NotFound(response, request)
}
func (p Handler) getServersHandler(response http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
providerID := getProviderIDFromVars(vars)
backendID := vars["backend"]
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
if backend, ok := provider.Backends[backendID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, backend.Servers)
if err != nil {
log.Error(err)
}
return
}
}
http.NotFound(response, request)
}
func (p Handler) getServerHandler(response http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
providerID := getProviderIDFromVars(vars)
backendID := vars["backend"]
serverID := vars["server"]
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
if backend, ok := provider.Backends[backendID]; ok {
if server, ok := backend.Servers[serverID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, server)
if err != nil {
log.Error(err)
}
return
}
}
}
http.NotFound(response, request)
}
func (p Handler) getFrontendsHandler(response http.ResponseWriter, request *http.Request) {
providerID := getProviderIDFromVars(mux.Vars(request))
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, provider.Frontends)
if err != nil {
log.Error(err)
}
} else {
http.NotFound(response, request)
}
}
func (p Handler) getFrontendHandler(response http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
providerID := getProviderIDFromVars(vars)
frontendID := vars["frontend"]
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
if frontend, ok := provider.Frontends[frontendID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, frontend)
if err != nil {
log.Error(err)
}
return
}
}
http.NotFound(response, request)
}
func (p Handler) getRoutesHandler(response http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
providerID := getProviderIDFromVars(vars)
frontendID := vars["frontend"]
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
if frontend, ok := provider.Frontends[frontendID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, frontend.Routes)
if err != nil {
log.Error(err)
}
return
}
}
http.NotFound(response, request)
}
func (p Handler) getRouteHandler(response http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
providerID := getProviderIDFromVars(vars)
frontendID := vars["frontend"]
routeID := vars["route"]
currentConfigurations := p.CurrentConfigurations.Get().(types.Configurations)
if provider, ok := currentConfigurations[providerID]; ok {
if frontend, ok := provider.Frontends[frontendID]; ok {
if route, ok := frontend.Routes[routeID]; ok {
err := templatesRenderer.JSON(response, http.StatusOK, route)
if err != nil {
log.Error(err)
}
return
}
}
}
http.NotFound(response, request)
}
// healthResponse combines data returned by thoas/stats with statistics (if
// they are enabled).
type healthResponse struct {
*thoas_stats.Data
*middlewares.Stats
}
func (p *Handler) getHealthHandler(response http.ResponseWriter, request *http.Request) {
health := &healthResponse{Data: p.Stats.Data()}
if p.StatsRecorder != nil {
health.Stats = p.StatsRecorder.Data()
}
err := templatesRenderer.JSON(response, http.StatusOK, health)
err := templateRenderer.JSON(rw, http.StatusOK, routers)
if err != nil {
log.Error(err)
log.FromContext(request.Context()).Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
func (p Handler) getRouterHandler(rw http.ResponseWriter, request *http.Request) {
providerID := mux.Vars(request)["provider"]
routerID := mux.Vars(request)["router"]
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
provider, ok := currentConfigurations[providerID]
if !ok {
http.NotFound(rw, request)
return
}
router, ok := provider.Routers[routerID]
if !ok {
http.NotFound(rw, request)
return
}
err := templateRenderer.JSON(rw, http.StatusOK, router)
if err != nil {
log.FromContext(request.Context()).Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
func (p Handler) getMiddlewaresHandler(rw http.ResponseWriter, request *http.Request) {
providerID := mux.Vars(request)["provider"]
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
provider, ok := currentConfigurations[providerID]
if !ok {
http.NotFound(rw, request)
return
}
var middlewares []MiddlewareRepresentation
for name, middleware := range provider.Middlewares {
middlewares = append(middlewares, MiddlewareRepresentation{Middleware: middleware, ID: name})
}
err := templateRenderer.JSON(rw, http.StatusOK, middlewares)
if err != nil {
log.FromContext(request.Context()).Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
func (p Handler) getMiddlewareHandler(rw http.ResponseWriter, request *http.Request) {
providerID := mux.Vars(request)["provider"]
middlewareID := mux.Vars(request)["middleware"]
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
provider, ok := currentConfigurations[providerID]
if !ok {
http.NotFound(rw, request)
return
}
middleware, ok := provider.Middlewares[middlewareID]
if !ok {
http.NotFound(rw, request)
return
}
err := templateRenderer.JSON(rw, http.StatusOK, middleware)
if err != nil {
log.FromContext(request.Context()).Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
func (p Handler) getServicesHandler(rw http.ResponseWriter, request *http.Request) {
providerID := mux.Vars(request)["provider"]
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
provider, ok := currentConfigurations[providerID]
if !ok {
http.NotFound(rw, request)
return
}
var services []ServiceRepresentation
for name, service := range provider.Services {
services = append(services, ServiceRepresentation{Service: service, ID: name})
}
err := templateRenderer.JSON(rw, http.StatusOK, services)
if err != nil {
log.FromContext(request.Context()).Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
func (p Handler) getServiceHandler(rw http.ResponseWriter, request *http.Request) {
providerID := mux.Vars(request)["provider"]
serviceID := mux.Vars(request)["service"]
currentConfigurations := p.CurrentConfigurations.Get().(config.Configurations)
provider, ok := currentConfigurations[providerID]
if !ok {
http.NotFound(rw, request)
return
}
service, ok := provider.Services[serviceID]
if !ok {
http.NotFound(rw, request)
return
}
err := templateRenderer.JSON(rw, http.StatusOK, service)
if err != nil {
log.FromContext(request.Context()).Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}

210
api/handler_test.go Normal file
View file

@ -0,0 +1,210 @@
package api
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"github.com/containous/mux"
"github.com/containous/traefik/config"
"github.com/containous/traefik/safe"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestHandler_Configuration(t *testing.T) {
type expected struct {
statusCode int
body string
}
testCases := []struct {
desc string
path string
configuration config.Configurations
expected expected
}{
{
desc: "Get all the providers",
path: "/api/providers",
configuration: config.Configurations{
"foo": {
Routers: map[string]*config.Router{
"bar": {EntryPoints: []string{"foo", "bar"}},
},
},
},
expected: expected{statusCode: http.StatusOK, body: `[{"id":"foo","path":"/api/providers/foo"}]`},
},
{
desc: "Get a provider",
path: "/api/providers/foo",
configuration: config.Configurations{
"foo": {
Routers: map[string]*config.Router{
"bar": {EntryPoints: []string{"foo", "bar"}},
},
Middlewares: map[string]*config.Middleware{
"bar": {
AddPrefix: &config.AddPrefix{Prefix: "bar"},
},
},
Services: map[string]*config.Service{
"foo": {
LoadBalancer: &config.LoadBalancerService{
Method: "wrr",
},
},
},
},
},
expected: expected{statusCode: http.StatusOK, body: `{"routers":[{"id":"bar","path":"/api/providers/foo/routers"}],"middlewares":[{"id":"bar","path":"/api/providers/foo/middlewares"}],"services":[{"id":"foo","path":"/api/providers/foo/services"}]}`},
},
{
desc: "Provider not found",
path: "/api/providers/foo",
configuration: config.Configurations{},
expected: expected{statusCode: http.StatusNotFound, body: "404 page not found\n"},
},
{
desc: "Get all routers",
path: "/api/providers/foo/routers",
configuration: config.Configurations{
"foo": {
Routers: map[string]*config.Router{
"bar": {EntryPoints: []string{"foo", "bar"}},
},
},
},
expected: expected{statusCode: http.StatusOK, body: `[{"entryPoints":["foo","bar"],"id":"bar"}]`},
},
{
desc: "Get a router",
path: "/api/providers/foo/routers/bar",
configuration: config.Configurations{
"foo": {
Routers: map[string]*config.Router{
"bar": {EntryPoints: []string{"foo", "bar"}},
},
},
},
expected: expected{statusCode: http.StatusOK, body: `{"entryPoints":["foo","bar"]}`},
},
{
desc: "Router not found",
path: "/api/providers/foo/routers/bar",
configuration: config.Configurations{
"foo": {},
},
expected: expected{statusCode: http.StatusNotFound, body: "404 page not found\n"},
},
{
desc: "Get all services",
path: "/api/providers/foo/services",
configuration: config.Configurations{
"foo": {
Services: map[string]*config.Service{
"foo": {
LoadBalancer: &config.LoadBalancerService{
Method: "wrr",
},
},
},
},
},
expected: expected{statusCode: http.StatusOK, body: `[{"loadbalancer":{"method":"wrr","passHostHeader":false},"id":"foo"}]`},
},
{
desc: "Get a service",
path: "/api/providers/foo/services/foo",
configuration: config.Configurations{
"foo": {
Services: map[string]*config.Service{
"foo": {
LoadBalancer: &config.LoadBalancerService{
Method: "wrr",
},
},
},
},
},
expected: expected{statusCode: http.StatusOK, body: `{"loadbalancer":{"method":"wrr","passHostHeader":false}}`},
},
{
desc: "Service not found",
path: "/api/providers/foo/services/bar",
configuration: config.Configurations{
"foo": {},
},
expected: expected{statusCode: http.StatusNotFound, body: "404 page not found\n"},
},
{
desc: "Get all middlewares",
path: "/api/providers/foo/middlewares",
configuration: config.Configurations{
"foo": {
Middlewares: map[string]*config.Middleware{
"bar": {
AddPrefix: &config.AddPrefix{Prefix: "bar"},
},
},
},
},
expected: expected{statusCode: http.StatusOK, body: `[{"addPrefix":{"prefix":"bar"},"id":"bar"}]`},
},
{
desc: "Get a middleware",
path: "/api/providers/foo/middlewares/bar",
configuration: config.Configurations{
"foo": {
Middlewares: map[string]*config.Middleware{
"bar": {
AddPrefix: &config.AddPrefix{Prefix: "bar"},
},
},
},
},
expected: expected{statusCode: http.StatusOK, body: `{"addPrefix":{"prefix":"bar"}}`},
},
{
desc: "Middleware not found",
path: "/api/providers/foo/middlewares/bar",
configuration: config.Configurations{
"foo": {},
},
expected: expected{statusCode: http.StatusNotFound, body: "404 page not found\n"},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
currentConfiguration := &safe.Safe{}
currentConfiguration.Set(test.configuration)
handler := Handler{
CurrentConfigurations: currentConfiguration,
}
router := mux.NewRouter()
handler.Append(router)
server := httptest.NewServer(router)
resp, err := http.DefaultClient.Get(server.URL + test.path)
require.NoError(t, err)
assert.Equal(t, test.expected.statusCode, resp.StatusCode)
content, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
err = resp.Body.Close()
require.NoError(t, err)
assert.Equal(t, test.expected.body, string(content))
})
}
}

View file

@ -8,8 +8,8 @@ import (
"github.com/cenk/backoff"
"github.com/containous/mux"
"github.com/containous/traefik/log"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/docker/leadership"
"github.com/unrolled/render"
)

View file

@ -5,10 +5,10 @@ import (
"github.com/containous/traefik/anonymize"
"github.com/containous/traefik/cmd"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/provider/file"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
)

View file

@ -4,32 +4,30 @@ import (
"time"
"github.com/containous/flaeg/parse"
"github.com/containous/traefik-extra-service-fabric"
"github.com/containous/traefik/api"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/middlewares/accesslog"
"github.com/containous/traefik/middlewares/tracing"
"github.com/containous/traefik/middlewares/tracing/datadog"
"github.com/containous/traefik/middlewares/tracing/jaeger"
"github.com/containous/traefik/middlewares/tracing/zipkin"
"github.com/containous/traefik/ping"
"github.com/containous/traefik/provider/boltdb"
"github.com/containous/traefik/provider/consul"
"github.com/containous/traefik/provider/consulcatalog"
"github.com/containous/traefik/provider/docker"
"github.com/containous/traefik/provider/dynamodb"
"github.com/containous/traefik/provider/ecs"
"github.com/containous/traefik/provider/etcd"
"github.com/containous/traefik/provider/eureka"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/provider/kubernetes"
"github.com/containous/traefik/provider/marathon"
"github.com/containous/traefik/provider/mesos"
"github.com/containous/traefik/provider/rancher"
"github.com/containous/traefik/provider/rest"
"github.com/containous/traefik/provider/zk"
"github.com/containous/traefik/types"
sf "github.com/jjcollinge/servicefabric"
"github.com/containous/traefik/old/api"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/middlewares/accesslog"
"github.com/containous/traefik/old/middlewares/tracing"
"github.com/containous/traefik/old/middlewares/tracing/datadog"
"github.com/containous/traefik/old/middlewares/tracing/jaeger"
"github.com/containous/traefik/old/middlewares/tracing/zipkin"
"github.com/containous/traefik/old/ping"
"github.com/containous/traefik/old/provider/boltdb"
"github.com/containous/traefik/old/provider/consul"
"github.com/containous/traefik/old/provider/consulcatalog"
"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/marathon"
"github.com/containous/traefik/old/provider/mesos"
"github.com/containous/traefik/old/provider/rancher"
"github.com/containous/traefik/old/provider/rest"
"github.com/containous/traefik/old/provider/zk"
"github.com/containous/traefik/old/types"
)
// TraefikConfiguration holds GlobalConfiguration and other stuff
@ -145,11 +143,6 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
var defaultEureka eureka.Provider
defaultEureka.RefreshSeconds = parse.Duration(30 * time.Second)
// default ServiceFabric
var defaultServiceFabric servicefabric.Provider
defaultServiceFabric.APIVersion = sf.DefaultAPIVersion
defaultServiceFabric.RefreshSeconds = 10
// default Ping
var defaultPing = ping.Handler{
EntryPoint: "traefik",

146
cmd/convert/convert.go Normal file
View file

@ -0,0 +1,146 @@
package main
import (
"os"
"strings"
"github.com/BurntSushi/toml"
"github.com/containous/traefik/config"
"github.com/containous/traefik/old/log"
"github.com/containous/traefik/old/types"
"github.com/sirupsen/logrus"
)
var oldvalue = `
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[backends.backend2]
[backends.backend2.servers.server1]
url = "http://127.0.0.1:9020"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[frontends.frontend2]
backend = "backend2"
[frontends.frontend2.routes.test_2]
rule = "Host:snitest.org"
`
// Temporary utility to convert dynamic conf v1 to v2
func main() {
log.SetOutput(os.Stdout)
log.SetLevel(logrus.DebugLevel)
oldconfig := &types.Configuration{}
toml.Decode(oldvalue, oldconfig)
newconfig := config.Configuration{
Routers: make(map[string]*config.Router),
Middlewares: make(map[string]*config.Middleware),
Services: make(map[string]*config.Service),
}
for frontendName, frontend := range oldconfig.Frontends {
newconfig.Routers[replaceFrontend(frontendName)] = convertFrontend(frontend)
if frontend.PassHostHeader {
log.Warn("ignore PassHostHeader")
}
}
for backendName, backend := range oldconfig.Backends {
newconfig.Services[replaceBackend(backendName)] = convertBackend(backend)
}
encoder := toml.NewEncoder(os.Stdout)
encoder.Encode(newconfig)
}
func replaceBackend(name string) string {
return strings.Replace(name, "backend", "service", -1)
}
func replaceFrontend(name string) string {
return strings.Replace(name, "frontend", "router", -1)
}
func convertFrontend(frontend *types.Frontend) *config.Router {
router := &config.Router{
EntryPoints: frontend.EntryPoints,
Middlewares: nil,
Service: replaceBackend(frontend.Backend),
Priority: frontend.Priority,
}
if len(frontend.Routes) > 1 {
log.Fatal("Multiple routes")
}
for _, route := range frontend.Routes {
router.Rule = route.Rule
}
return router
}
func convertBackend(backend *types.Backend) *config.Service {
service := &config.Service{
LoadBalancer: &config.LoadBalancerService{
Stickiness: nil,
Servers: nil,
Method: "",
HealthCheck: nil,
PassHostHeader: false,
},
}
if backend.Buffering != nil {
log.Warn("Buffering not implemented")
}
if backend.CircuitBreaker != nil {
log.Warn("CircuitBreaker not implemented")
}
if backend.MaxConn != nil {
log.Warn("MaxConn not implemented")
}
for _, oldserver := range backend.Servers {
service.LoadBalancer.Servers = append(service.LoadBalancer.Servers, config.Server{
URL: oldserver.URL,
Weight: oldserver.Weight,
})
}
if backend.LoadBalancer != nil {
service.LoadBalancer.Method = backend.LoadBalancer.Method
if backend.LoadBalancer.Stickiness != nil {
service.LoadBalancer.Stickiness = &config.Stickiness{
CookieName: backend.LoadBalancer.Stickiness.CookieName,
}
}
if backend.HealthCheck != nil {
service.LoadBalancer.HealthCheck = &config.HealthCheck{
Scheme: backend.HealthCheck.Scheme,
Path: backend.HealthCheck.Path,
Port: backend.HealthCheck.Port,
Interval: backend.HealthCheck.Interval,
Timeout: backend.HealthCheck.Timeout,
Hostname: backend.HealthCheck.Hostname,
Headers: backend.HealthCheck.Headers,
}
}
}
return service
}

View file

@ -10,7 +10,7 @@ import (
"github.com/containous/flaeg"
"github.com/containous/traefik/cmd"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/old/configuration"
)
// NewCmd builds a new HealthCheck command

View file

@ -21,17 +21,20 @@ import (
"github.com/containous/traefik/cmd/storeconfig"
cmdVersion "github.com/containous/traefik/cmd/version"
"github.com/containous/traefik/collector"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/configuration/router"
"github.com/containous/traefik/config"
"github.com/containous/traefik/config/static"
"github.com/containous/traefik/job"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider/ecs"
"github.com/containous/traefik/provider/kubernetes"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/old/provider/ecs"
"github.com/containous/traefik/old/provider/kubernetes"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/provider/aggregator"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/server"
"github.com/containous/traefik/server/router"
"github.com/containous/traefik/server/uuid"
traefiktls "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
"github.com/coreos/go-systemd/daemon"
"github.com/elazarl/go-bindata-assetfs"
@ -186,7 +189,7 @@ func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile s
stats(globalConfiguration)
providerAggregator := configuration.NewProviderAggregator(globalConfiguration)
providerAggregator := aggregator.NewProviderAggregator(static.ConvertStaticConf(*globalConfiguration))
acmeProvider, err := globalConfiguration.InitACMEProvider()
if err != nil {
@ -199,18 +202,15 @@ func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile s
}
entryPoints := map[string]server.EntryPoint{}
staticConf := static.ConvertStaticConf(*globalConfiguration)
for entryPointName, config := range globalConfiguration.EntryPoints {
factory := router.NewRouteAppenderFactory(staticConf, entryPointName, acmeProvider)
entryPoint := server.EntryPoint{
Configuration: config,
RouteAppenderFactory: factory,
Configuration: config,
}
internalRouter := router.NewInternalRouterAggregator(*globalConfiguration, entryPointName)
if acmeProvider != nil {
if acmeProvider.HTTPChallenge != nil && entryPointName == acmeProvider.HTTPChallenge.EntryPoint {
internalRouter.AddRouter(acmeProvider)
}
// TLS ALPN 01
if acmeProvider.TLSChallenge != nil && acmeProvider.HTTPChallenge == nil && acmeProvider.DNSChallenge == nil {
entryPoint.TLSALPNGetter = acmeProvider.GetTLSALPNCertificate
@ -227,19 +227,19 @@ func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile s
}
}
entryPoint.InternalRouter = internalRouter
entryPoints[entryPointName] = entryPoint
}
svr := server.NewServer(*globalConfiguration, providerAggregator, entryPoints)
if acmeProvider != nil && acmeProvider.OnHostRule {
acmeProvider.SetConfigListenerChan(make(chan types.Configuration))
acmeProvider.SetConfigListenerChan(make(chan config.Configuration))
svr.AddListener(acmeProvider.ListenConfiguration)
}
ctx := cmd.ContextWithSignal(context.Background())
if globalConfiguration.Ping != nil {
globalConfiguration.Ping.WithContext(ctx)
if staticConf.Ping != nil {
staticConf.Ping.WithContext(ctx)
}
svr.StartWithContext(ctx)

View file

@ -10,8 +10,8 @@ import (
"time"
"github.com/containous/traefik/anonymize"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/log"
"github.com/containous/traefik/old/configuration"
"github.com/containous/traefik/version"
"github.com/mitchellh/hashstructure"
)

160
config/dyn_config.go Normal file
View file

@ -0,0 +1,160 @@
package config
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
traefiktls "github.com/containous/traefik/tls"
)
// Router holds the router configuration.
type Router struct {
EntryPoints []string `json:"entryPoints"`
Middlewares []string `json:"middlewares,omitempty" toml:",omitempty"`
Service string `json:"service,omitempty" toml:",omitempty"`
Rule string `json:"rule,omitempty" toml:",omitempty"`
Priority int `json:"priority,omitempty" toml:"priority,omitzero"`
}
// LoadBalancerService holds the LoadBalancerService configuration.
type LoadBalancerService struct {
Stickiness *Stickiness `json:"stickiness,omitempty" toml:",omitempty"`
Servers []Server `json:"servers,omitempty" toml:",omitempty"`
Method string `json:"method,omitempty" toml:",omitempty"`
HealthCheck *HealthCheck `json:"healthCheck,omitempty" toml:",omitempty"`
PassHostHeader bool `json:"passHostHeader" toml:",omitempty"`
ResponseForwarding *ResponseForwarding `json:"forwardingResponse,omitempty" toml:",omitempty"`
}
// ResponseForwarding holds configuration for the forward of the response.
type ResponseForwarding struct {
FlushInterval string `json:"flushInterval,omitempty" toml:",omitempty"`
}
// Stickiness holds the stickiness configuration.
type Stickiness struct {
CookieName string `json:"cookieName,omitempty" toml:",omitempty"`
}
// Server holds the server configuration.
type Server struct {
URL string `json:"url"`
Weight int `json:"weight"`
}
// HealthCheck holds the HealthCheck configuration.
type HealthCheck struct {
Scheme string `json:"scheme,omitempty" toml:",omitempty"`
Path string `json:"path,omitempty" toml:",omitempty"`
Port int `json:"port,omitempty" toml:",omitempty,omitzero"`
// FIXME change string to parse.Duration
Interval string `json:"interval,omitempty" toml:",omitempty"`
// FIXME change string to parse.Duration
Timeout string `json:"timeout,omitempty" toml:",omitempty"`
Hostname string `json:"hostname,omitempty" toml:",omitempty"`
Headers map[string]string `json:"headers,omitempty" toml:",omitempty"`
}
// ClientTLS holds the TLS specific configurations as client
// CA, Cert and Key can be either path or file contents.
type ClientTLS struct {
CA string `description:"TLS CA" json:"ca,omitempty"`
CAOptional bool `description:"TLS CA.Optional" json:"caOptional,omitempty"`
Cert string `description:"TLS cert" json:"cert,omitempty"`
Key string `description:"TLS key" json:"key,omitempty"`
InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty"`
}
// CreateTLSConfig creates a TLS config from ClientTLS structures.
func (clientTLS *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
if clientTLS == nil {
return nil, nil
}
var err error
caPool := x509.NewCertPool()
clientAuth := tls.NoClientCert
if clientTLS.CA != "" {
var ca []byte
if _, errCA := os.Stat(clientTLS.CA); errCA == nil {
ca, err = ioutil.ReadFile(clientTLS.CA)
if err != nil {
return nil, fmt.Errorf("failed to read CA. %s", err)
}
} else {
ca = []byte(clientTLS.CA)
}
if !caPool.AppendCertsFromPEM(ca) {
return nil, fmt.Errorf("failed to parse CA")
}
if clientTLS.CAOptional {
clientAuth = tls.VerifyClientCertIfGiven
} else {
clientAuth = tls.RequireAndVerifyClientCert
}
}
cert := tls.Certificate{}
_, errKeyIsFile := os.Stat(clientTLS.Key)
if !clientTLS.InsecureSkipVerify && (len(clientTLS.Cert) == 0 || len(clientTLS.Key) == 0) {
return nil, fmt.Errorf("TLS Certificate or Key file must be set when TLS configuration is created")
}
if len(clientTLS.Cert) > 0 && len(clientTLS.Key) > 0 {
if _, errCertIsFile := os.Stat(clientTLS.Cert); errCertIsFile == nil {
if errKeyIsFile == nil {
cert, err = tls.LoadX509KeyPair(clientTLS.Cert, clientTLS.Key)
if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %v", err)
}
} else {
return nil, fmt.Errorf("tls cert is a file, but tls key is not")
}
} else {
if errKeyIsFile != nil {
cert, err = tls.X509KeyPair([]byte(clientTLS.Cert), []byte(clientTLS.Key))
if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %v", err)
}
} else {
return nil, fmt.Errorf("TLS key is a file, but tls cert is not")
}
}
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caPool,
InsecureSkipVerify: clientTLS.InsecureSkipVerify,
ClientAuth: clientAuth,
}, nil
}
// Message holds configuration information exchanged between parts of traefik.
type Message struct {
ProviderName string
Configuration *Configuration
}
// Configurations is for currentConfigurations Map.
type Configurations map[string]*Configuration
// Configuration FIXME better name?
type Configuration struct {
Routers map[string]*Router `json:"routers,omitempty" toml:",omitempty"`
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:",omitempty"`
Services map[string]*Service `json:"services,omitempty" toml:",omitempty"`
TLS []*traefiktls.Configuration `json:"-"`
}
// Service holds a service configuration (can only be of one type at the same time).
type Service struct {
LoadBalancer *LoadBalancerService `json:"loadbalancer,omitempty" toml:",omitempty,omitzero"`
}

274
config/middlewares.go Normal file
View file

@ -0,0 +1,274 @@
package config
import (
"github.com/containous/flaeg/parse"
"github.com/containous/traefik/ip"
)
// Middleware holds the Middleware configuration.
type Middleware struct {
AddPrefix *AddPrefix `json:"addPrefix,omitempty"`
StripPrefix *StripPrefix `json:"stripPrefix,omitempty"`
StripPrefixRegex *StripPrefixRegex `json:"stripPrefixRegex,omitempty"`
ReplacePath *ReplacePath `json:"replacePath,omitempty"`
ReplacePathRegex *ReplacePathRegex `json:"replacePathRegex,omitempty"`
Chain *Chain `json:"chain,omitempty"`
IPWhiteList *IPWhiteList `json:"ipWhiteList,omitempty"`
Headers *Headers `json:"headers,omitempty"`
Errors *ErrorPage `json:"errors,omitempty"`
RateLimit *RateLimit `json:"rateLimit,omitempty"`
Redirect *Redirect `json:"redirect,omitempty"`
BasicAuth *BasicAuth `json:"basicAuth,omitempty"`
DigestAuth *DigestAuth `json:"digestAuth,omitempty"`
ForwardAuth *ForwardAuth `json:"forwardAuth,omitempty"`
MaxConn *MaxConn `json:"maxConn,omitempty"`
Buffering *Buffering `json:"buffering,omitempty"`
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty"`
Compress *Compress `json:"compress,omitempty"`
PassTLSClientCert *PassTLSClientCert `json:"passTLSClientCert,omitempty"`
Retry *Retry `json:"retry,omitempty"`
}
// AddPrefix holds the AddPrefix configuration.
type AddPrefix struct {
Prefix string `json:"prefix,omitempty"`
}
// Auth holds the authentication configuration (BASIC, DIGEST, users).
type Auth struct {
Basic *BasicAuth `json:"basic,omitempty" export:"true"`
Digest *DigestAuth `json:"digest,omitempty" export:"true"`
Forward *ForwardAuth `json:"forward,omitempty" export:"true"`
}
// BasicAuth holds the HTTP basic authentication configuration.
type BasicAuth struct {
Users `json:"users,omitempty" mapstructure:","`
UsersFile string `json:"usersFile,omitempty"`
Realm string `json:"realm,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty"`
HeaderField string `json:"headerField,omitempty" export:"true"`
}
// Buffering holds the request/response buffering configuration.
type Buffering struct {
MaxRequestBodyBytes int64 `json:"maxRequestBodyBytes,omitempty"`
MemRequestBodyBytes int64 `json:"memRequestBodyBytes,omitempty"`
MaxResponseBodyBytes int64 `json:"maxResponseBodyBytes,omitempty"`
MemResponseBodyBytes int64 `json:"memResponseBodyBytes,omitempty"`
RetryExpression string `json:"retryExpression,omitempty"`
}
// Chain holds a chain of middlewares
type Chain struct {
Middlewares []string `json:"middlewares"`
}
// CircuitBreaker holds the circuit breaker configuration.
type CircuitBreaker struct {
Expression string `json:"expression,omitempty"`
}
// Compress holds the compress configuration.
type Compress struct{}
// DigestAuth holds the Digest HTTP authentication configuration.
type DigestAuth struct {
Users `json:"users,omitempty" mapstructure:","`
UsersFile string `json:"usersFile,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty"`
Realm string `json:"realm,omitempty" mapstructure:","`
HeaderField string `json:"headerField,omitempty" export:"true"`
}
// ErrorPage holds the custom error page configuration.
type ErrorPage struct {
Status []string `json:"status,omitempty"`
Service string `json:"service,omitempty"`
Query string `json:"query,omitempty"`
}
// ForwardAuth holds the http forward authentication configuration.
type ForwardAuth struct {
Address string `description:"Authentication server address" json:"address,omitempty"`
TLS *ClientTLS `description:"Enable TLS support" json:"tls,omitempty" export:"true"`
TrustForwardHeader bool `description:"Trust X-Forwarded-* headers" json:"trustForwardHeader,omitempty" export:"true"`
AuthResponseHeaders []string `description:"Headers to be forwarded from auth response" json:"authResponseHeaders,omitempty"`
}
// Headers holds the custom header configuration.
type Headers struct {
CustomRequestHeaders map[string]string `json:"customRequestHeaders,omitempty"`
CustomResponseHeaders map[string]string `json:"customResponseHeaders,omitempty"`
AllowedHosts []string `json:"allowedHosts,omitempty"`
HostsProxyHeaders []string `json:"hostsProxyHeaders,omitempty"`
SSLRedirect bool `json:"sslRedirect,omitempty"`
SSLTemporaryRedirect bool `json:"sslTemporaryRedirect,omitempty"`
SSLHost string `json:"sslHost,omitempty"`
SSLProxyHeaders map[string]string `json:"sslProxyHeaders,omitempty"`
SSLForceHost bool `json:"sslForceHost,omitempty"`
STSSeconds int64 `json:"stsSeconds,omitempty"`
STSIncludeSubdomains bool `json:"stsIncludeSubdomains,omitempty"`
STSPreload bool `json:"stsPreload,omitempty"`
ForceSTSHeader bool `json:"forceSTSHeader,omitempty"`
FrameDeny bool `json:"frameDeny,omitempty"`
CustomFrameOptionsValue string `json:"customFrameOptionsValue,omitempty"`
ContentTypeNosniff bool `json:"contentTypeNosniff,omitempty"`
BrowserXSSFilter bool `json:"browserXssFilter,omitempty"`
CustomBrowserXSSValue string `json:"customBrowserXSSValue,omitempty"`
ContentSecurityPolicy string `json:"contentSecurityPolicy,omitempty"`
PublicKey string `json:"publicKey,omitempty"`
ReferrerPolicy string `json:"referrerPolicy,omitempty"`
IsDevelopment bool `json:"isDevelopment,omitempty"`
}
// HasCustomHeadersDefined checks to see if any of the custom header elements have been set
func (h *Headers) HasCustomHeadersDefined() bool {
return h != nil && (len(h.CustomResponseHeaders) != 0 ||
len(h.CustomRequestHeaders) != 0)
}
// HasSecureHeadersDefined checks to see if any of the secure header elements have been set
func (h *Headers) HasSecureHeadersDefined() bool {
return h != nil && (len(h.AllowedHosts) != 0 ||
len(h.HostsProxyHeaders) != 0 ||
h.SSLRedirect ||
h.SSLTemporaryRedirect ||
h.SSLForceHost ||
h.SSLHost != "" ||
len(h.SSLProxyHeaders) != 0 ||
h.STSSeconds != 0 ||
h.STSIncludeSubdomains ||
h.STSPreload ||
h.ForceSTSHeader ||
h.FrameDeny ||
h.CustomFrameOptionsValue != "" ||
h.ContentTypeNosniff ||
h.BrowserXSSFilter ||
h.CustomBrowserXSSValue != "" ||
h.ContentSecurityPolicy != "" ||
h.PublicKey != "" ||
h.ReferrerPolicy != "" ||
h.IsDevelopment)
}
// IPStrategy holds the ip strategy configuration.
type IPStrategy struct {
Depth int `json:"depth,omitempty" export:"true"`
ExcludedIPs []string `json:"excludedIPs,omitempty"`
}
// Get an IP selection strategy
// if nil return the RemoteAddr strategy
// else return a strategy base on the configuration using the X-Forwarded-For Header.
// Depth override the ExcludedIPs
func (s *IPStrategy) Get() (ip.Strategy, error) {
if s == nil {
return &ip.RemoteAddrStrategy{}, nil
}
if s.Depth > 0 {
return &ip.DepthStrategy{
Depth: s.Depth,
}, nil
}
if len(s.ExcludedIPs) > 0 {
checker, err := ip.NewChecker(s.ExcludedIPs)
if err != nil {
return nil, err
}
return &ip.CheckerStrategy{
Checker: checker,
}, nil
}
return &ip.RemoteAddrStrategy{}, nil
}
// IPWhiteList holds the ip white list configuration.
type IPWhiteList struct {
SourceRange []string `json:"sourceRange,omitempty"`
IPStrategy *IPStrategy `json:"ipStrategy,omitempty"`
}
// MaxConn holds maximum connection configuration.
type MaxConn struct {
Amount int64 `json:"amount,omitempty"`
ExtractorFunc string `json:"extractorFunc,omitempty"`
}
// PassTLSClientCert holds the TLS client cert headers configuration.
type PassTLSClientCert struct {
PEM bool `description:"Enable header with escaped client pem" json:"pem"`
Infos *TLSClientCertificateInfos `description:"Enable header with configured client cert infos" json:"infos,omitempty"`
}
// Rate holds the rate limiting configuration for a specific time period.
type Rate struct {
Period parse.Duration `json:"period,omitempty"`
Average int64 `json:"average,omitempty"`
Burst int64 `json:"burst,omitempty"`
}
// RateLimit holds the rate limiting configuration for a given frontend.
type RateLimit struct {
RateSet map[string]*Rate `json:"rateset,omitempty"`
// FIXME replace by ipStrategy see oxy and replace
ExtractorFunc string `json:"extractorFunc,omitempty"`
}
// Redirect holds the redirection configuration of an entry point to another, or to an URL.
type Redirect struct {
Regex string `json:"regex,omitempty"`
Replacement string `json:"replacement,omitempty"`
Permanent bool `json:"permanent,omitempty"`
}
// ReplacePath holds the ReplacePath configuration.
type ReplacePath struct {
Path string `json:"path,omitempty"`
}
// ReplacePathRegex holds the ReplacePathRegex configuration.
type ReplacePathRegex struct {
Regex string `json:"regex,omitempty"`
Replacement string `json:"replacement,omitempty"`
}
// Retry contains request retry config
type Retry struct {
Attempts int `description:"Number of attempts" export:"true"`
}
// StripPrefix holds the StripPrefix configuration.
type StripPrefix struct {
Prefixes []string `json:"prefixes,omitempty"`
}
// StripPrefixRegex holds the StripPrefixRegex configuration.
type StripPrefixRegex struct {
Regex []string `json:"regex,omitempty"`
}
// TLSClientCertificateInfos holds the client TLS certificate infos configuration.
type TLSClientCertificateInfos struct {
NotAfter bool `description:"Add NotAfter info in header" json:"notAfter"`
NotBefore bool `description:"Add NotBefore info in header" json:"notBefore"`
Subject *TLSCLientCertificateSubjectInfos `description:"Add Subject info in header" json:"subject,omitempty"`
Sans bool `description:"Add Sans info in header" json:"sans"`
}
// TLSCLientCertificateSubjectInfos holds the client TLS certificate subject infos configuration.
type TLSCLientCertificateSubjectInfos struct {
Country bool `description:"Add Country info in header" json:"country"`
Province bool `description:"Add Province info in header" json:"province"`
Locality bool `description:"Add Locality info in header" json:"locality"`
Organization bool `description:"Add Organization info in header" json:"organization"`
CommonName bool `description:"Add CommonName info in header" json:"commonName"`
SerialNumber bool `description:"Add SerialNumber info in header" json:"serialNumber"`
}
// Users holds a list of users
type Users []string

246
config/static/convert.go Normal file
View file

@ -0,0 +1,246 @@
package static
import (
oldapi "github.com/containous/traefik/old/api"
"github.com/containous/traefik/old/configuration"
oldtracing "github.com/containous/traefik/old/middlewares/tracing"
oldfile "github.com/containous/traefik/old/provider/file"
oldtypes "github.com/containous/traefik/old/types"
"github.com/containous/traefik/ping"
"github.com/containous/traefik/provider"
"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"
)
// ConvertStaticConf FIXME sugar
// Deprecated
func ConvertStaticConf(globalConfiguration configuration.GlobalConfiguration) Configuration {
staticConfiguration := Configuration{}
staticConfiguration.EntryPoints = &EntryPoints{
EntryPointList: make(EntryPointList),
Defaults: globalConfiguration.DefaultEntryPoints,
}
if globalConfiguration.EntryPoints != nil {
for name, ep := range globalConfiguration.EntryPoints {
staticConfiguration.EntryPoints.EntryPointList[name] = EntryPoint{
Address: ep.Address,
}
}
}
if globalConfiguration.Ping != nil {
old := globalConfiguration.Ping
staticConfiguration.Ping = &ping.Handler{
EntryPoint: old.EntryPoint,
}
}
staticConfiguration.API = convertAPI(globalConfiguration.API)
staticConfiguration.Constraints = convertConstraints(globalConfiguration.Constraints)
staticConfiguration.File = convertFile(globalConfiguration.File)
staticConfiguration.Metrics = ConvertMetrics(globalConfiguration.Metrics)
staticConfiguration.AccessLog = ConvertAccessLog(globalConfiguration.AccessLog)
staticConfiguration.Tracing = ConvertTracing(globalConfiguration.Tracing)
staticConfiguration.HostResolver = ConvertHostResolverConfig(globalConfiguration.HostResolver)
return staticConfiguration
}
// ConvertAccessLog FIXME sugar
// Deprecated
func ConvertAccessLog(old *oldtypes.AccessLog) *types.AccessLog {
if old == nil {
return nil
}
accessLog := &types.AccessLog{
FilePath: old.FilePath,
Format: old.Format,
BufferingSize: old.BufferingSize,
}
if old.Filters != nil {
accessLog.Filters = &types.AccessLogFilters{
StatusCodes: types.StatusCodes(old.Filters.StatusCodes),
RetryAttempts: old.Filters.RetryAttempts,
MinDuration: old.Filters.MinDuration,
}
}
if old.Fields != nil {
accessLog.Fields = &types.AccessLogFields{
DefaultMode: old.Fields.DefaultMode,
Names: types.FieldNames(old.Fields.Names),
}
if old.Fields.Headers != nil {
accessLog.Fields.Headers = &types.FieldHeaders{
DefaultMode: old.Fields.Headers.DefaultMode,
Names: types.FieldHeaderNames(old.Fields.Headers.Names),
}
}
}
return accessLog
}
// ConvertMetrics FIXME sugar
// Deprecated
func ConvertMetrics(old *oldtypes.Metrics) *types.Metrics {
if old == nil {
return nil
}
metrics := &types.Metrics{}
if old.Prometheus != nil {
metrics.Prometheus = &types.Prometheus{
EntryPoint: old.Prometheus.EntryPoint,
Buckets: types.Buckets(old.Prometheus.Buckets),
}
}
if old.Datadog != nil {
metrics.Datadog = &types.Datadog{
Address: old.Datadog.Address,
PushInterval: old.Datadog.PushInterval,
}
}
if old.StatsD != nil {
metrics.StatsD = &types.Statsd{
Address: old.StatsD.Address,
PushInterval: old.StatsD.PushInterval,
}
}
if old.InfluxDB != nil {
metrics.InfluxDB = &types.InfluxDB{
Address: old.InfluxDB.Address,
Protocol: old.InfluxDB.Protocol,
PushInterval: old.InfluxDB.PushInterval,
Database: old.InfluxDB.Database,
RetentionPolicy: old.InfluxDB.RetentionPolicy,
Username: old.InfluxDB.Username,
Password: old.InfluxDB.Password,
}
}
return metrics
}
// ConvertTracing FIXME sugar
// Deprecated
func ConvertTracing(old *oldtracing.Tracing) *Tracing {
if old == nil {
return nil
}
tra := &Tracing{
Backend: old.Backend,
ServiceName: old.ServiceName,
SpanNameLimit: old.SpanNameLimit,
}
if old.Jaeger != nil {
tra.Jaeger = &jaeger.Config{
SamplingServerURL: old.Jaeger.SamplingServerURL,
SamplingType: old.Jaeger.SamplingType,
SamplingParam: old.Jaeger.SamplingParam,
LocalAgentHostPort: old.Jaeger.LocalAgentHostPort,
Gen128Bit: old.Jaeger.Gen128Bit,
Propagation: old.Jaeger.Propagation,
}
}
if old.Zipkin != nil {
tra.Zipkin = &zipkin.Config{
HTTPEndpoint: old.Zipkin.HTTPEndpoint,
SameSpan: old.Zipkin.SameSpan,
ID128Bit: old.Zipkin.ID128Bit,
Debug: old.Zipkin.Debug,
}
}
if old.DataDog != nil {
tra.DataDog = &datadog.Config{
LocalAgentHostPort: old.DataDog.LocalAgentHostPort,
GlobalTag: old.DataDog.GlobalTag,
Debug: old.DataDog.Debug,
}
}
return tra
}
func convertAPI(old *oldapi.Handler) *API {
if old == nil {
return nil
}
api := &API{
EntryPoint: old.EntryPoint,
Dashboard: old.Dashboard,
DashboardAssets: old.DashboardAssets,
}
if old.Statistics != nil {
api.Statistics = &types.Statistics{
RecentErrors: old.Statistics.RecentErrors,
}
}
return api
}
func convertConstraints(oldConstraints oldtypes.Constraints) types.Constraints {
constraints := types.Constraints{}
for _, value := range oldConstraints {
constraint := &types.Constraint{
Key: value.Key,
MustMatch: value.MustMatch,
Regex: value.Regex,
}
constraints = append(constraints, constraint)
}
return constraints
}
func convertFile(old *oldfile.Provider) *file.Provider {
if old == nil {
return nil
}
f := &file.Provider{
BaseProvider: provider.BaseProvider{
Watch: old.Watch,
Filename: old.Filename,
Trace: old.Trace,
},
Directory: old.Directory,
TraefikFile: old.TraefikFile,
}
f.DebugLogGeneratedTemplate = old.DebugLogGeneratedTemplate
f.Constraints = convertConstraints(old.Constraints)
return f
}
// ConvertHostResolverConfig FIXME
// Deprecated
func ConvertHostResolverConfig(oldconfig *configuration.HostResolverConfig) *HostResolverConfig {
if oldconfig == nil {
return nil
}
return &HostResolverConfig{
CnameFlattening: oldconfig.CnameFlattening,
ResolvConfig: oldconfig.ResolvConfig,
ResolvDepth: oldconfig.ResolvDepth,
}
}

View file

@ -0,0 +1,113 @@
package static
import (
"github.com/containous/flaeg/parse"
"github.com/containous/traefik/ping"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/tracing/datadog"
"github.com/containous/traefik/tracing/jaeger"
"github.com/containous/traefik/tracing/zipkin"
"github.com/containous/traefik/types"
"github.com/elazarl/go-bindata-assetfs"
)
// Configuration FIXME temp static configuration
type Configuration struct {
Global *Global
EntryPoints *EntryPoints
API *API `description:"Enable api/dashboard" export:"true"`
Metrics *types.Metrics `description:"Enable a metrics exporter" export:"true"`
Ping *ping.Handler `description:"Enable ping" export:"true"`
// Rest *rest.Provider `description:"Enable Rest backend with default settings" export:"true"`
Log *types.TraefikLog
AccessLog *types.AccessLog `description:"Access log settings" export:"true"`
Tracing *Tracing `description:"OpenTracing configuration" export:"true"`
File *file.Provider `description:"Enable File backend with default settings" export:"true"`
Constraints types.Constraints `description:"Filter services by constraint, matching with service tags" export:"true"`
HostResolver *HostResolverConfig `description:"Enable CNAME Flattening" export:"true"`
// TODO
// ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
// Retry *Retry `description:"Enable retry sending request if network error" export:"true"`
// HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"`
//
}
// Global holds the global configuration.
type Global struct {
Debug bool `short:"d" description:"Enable debug mode" export:"true"`
CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"`
SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"`
InsecureSkipVerify bool `description:"Disable SSL certificate verification" export:"true"`
RootCAs tls.FilesOrContents `description:"Add cert file for self-signed certificate"`
ProvidersThrottleDuration parse.Duration `description:"Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time." export:"true"`
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"`
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers" export:"true"`
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" export:"true"`
}
// API holds the API configuration
type API struct {
EntryPoint string `description:"EntryPoint" export:"true"`
Dashboard bool `description:"Activate dashboard" export:"true"`
Statistics *types.Statistics `description:"Enable more detailed statistics" export:"true"`
Middlewares []string `description:"Middleware list" export:"true"`
DashboardAssets *assetfs.AssetFS `json:"-"`
}
// RespondingTimeouts contains timeout configurations for incoming requests to the Traefik instance.
type RespondingTimeouts struct {
ReadTimeout parse.Duration `description:"ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set" export:"true"`
WriteTimeout parse.Duration `description:"WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set" export:"true"`
IdleTimeout parse.Duration `description:"IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. Defaults to 180 seconds. If zero, no timeout is set" export:"true"`
}
// ForwardingTimeouts contains timeout configurations for forwarding requests to the backend servers.
type ForwardingTimeouts struct {
DialTimeout parse.Duration `description:"The amount of time to wait until a connection to a backend server can be established. Defaults to 30 seconds. If zero, no timeout exists" export:"true"`
ResponseHeaderTimeout parse.Duration `description:"The amount of time to wait for a server's response headers after fully writing the request (including its body, if any). If zero, no timeout exists" export:"true"`
}
// LifeCycle contains configurations relevant to the lifecycle (such as the shutdown phase) of Traefik.
type LifeCycle struct {
RequestAcceptGraceTimeout parse.Duration `description:"Duration to keep accepting requests before Traefik initiates the graceful shutdown procedure"`
GraceTimeOut parse.Duration `description:"Duration to give active requests a chance to finish before Traefik stops"`
}
// EntryPoint holds the entry point configuration
type EntryPoint struct {
Address string
}
// EntryPointList holds the HTTP entry point list type.
type EntryPointList map[string]EntryPoint
// EntryPoints holds the entry points configuration.
type EntryPoints struct {
EntryPointList
Defaults []string
}
// Tracing holds the tracing configuration.
type Tracing struct {
Backend string `description:"Selects the tracking backend ('jaeger','zipkin', 'datadog')." export:"true"`
ServiceName string `description:"Set the name for this service" export:"true"`
SpanNameLimit int `description:"Set the maximum character limit for Span names (default 0 = no limit)" export:"true"`
Jaeger *jaeger.Config `description:"Settings for jaeger"`
Zipkin *zipkin.Config `description:"Settings for zipkin"`
DataDog *datadog.Config `description:"Settings for DataDog"`
}
// HostResolverConfig contain configuration for CNAME Flattening.
type HostResolverConfig struct {
CnameFlattening bool `description:"A flag to enable/disable CNAME flattening" 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"`
}

View file

@ -83,7 +83,7 @@ If you encounter 'too many open files' errors, you can either increase this valu
- `defaultEntryPoints`: Entrypoints to be used by frontends that do not specify any entrypoint.
Each frontend can specify its own entrypoints.
- `keepTrailingSlash`: Tells Træfik whether it should keep the trailing slashes that might be present in the paths of incoming requests (true), or if it should redirect to the slashless version of the URL (default behavior: false)
- `keepTrailingSlash`: Tells Traefik whether it should keep the trailing slashes that might be present in the paths of incoming requests (true), or if it should redirect to the slashless version of the URL (default behavior: false)
!!! note
Beware that the value of `keepTrailingSlash` can have a significant impact on the way your frontend rules are interpreted.

View file

@ -486,7 +486,7 @@ Responses are compressed when:
## White Listing
Træfik supports whitelisting to accept or refuse requests based on the client IP.
Traefik supports whitelisting to accept or refuse requests based on the client IP.
The following example enables IP white listing and accepts requests from client IPs defined in `sourceRange`.
@ -501,7 +501,7 @@ The following example enables IP white listing and accepts requests from client
# Override the clientIPStrategy
```
By default, Træfik uses the client IP (see [ClientIPStrategy](/configuration/entrypoints/#clientipstrategy)) for the whitelisting.
By default, Traefik uses the client IP (see [ClientIPStrategy](/configuration/entrypoints/#clientipstrategy)) for the whitelisting.
If you want to use another IP than the one determined by `ClientIPStrategy` for the whitelisting, you can define the `IPStrategy` option:
@ -522,7 +522,7 @@ In the above example, if the value of the `X-Forwarded-For` header was `"10.0.0.
## ClientIPStrategy
The `clientIPStrategy` defines how you want Træfik to determine the client IP (used for whitelisting for example).
The `clientIPStrategy` defines how you want Traefik to determine the client IP (used for whitelisting for example).
There are several option available:
@ -560,7 +560,7 @@ Examples:
### Excluded IPs
Træfik will scan the `X-Forwarded-For` header (from the right) and pick the first IP not in the `excludedIPs` list.
Traefik will scan the `X-Forwarded-For` header (from the right) and pick the first IP not in the `excludedIPs` list.
```toml
[entryPoints]
@ -586,7 +586,7 @@ Examples:
### Default
If there are no `depth` or `excludedIPs`, then the client IP is the IP of the computer that initiated the connection with the Træfik server (the remote address).
If there are no `depth` or `excludedIPs`, then the client IP is the IP of the computer that initiated the connection with the Traefik server (the remote address).
## ProxyProtocol

View file

@ -114,7 +114,7 @@ func initH2CWithPriorKnowledge(w http.ResponseWriter) (net.Conn, error) {
conn.Close()
if http2VerboseLogs {
log.Printf(
log.Infof(
"Missing the request body portion of the client preface. Wanted: %v Got: %v",
[]byte(expectedBody),
buf[0:n],

View file

@ -131,50 +131,58 @@ func (hc *HealthCheck) execute(ctx context.Context, backend *BackendConfig) {
func (hc *HealthCheck) checkBackend(backend *BackendConfig) {
enabledURLs := backend.LB.Servers()
var newDisabledURLs []*url.URL
// FIXME re enable metrics
for _, disableURL := range backend.disabledURLs {
serverUpMetricValue := float64(0)
//serverUpMetricValue := float64(0)
if err := checkHealth(disableURL, backend); err == nil {
log.Warnf("Health check up: Returning to server list. Backend: %q URL: %q", backend.name, disableURL.String())
if err := backend.LB.UpsertServer(disableURL, roundrobin.Weight(1)); err != nil {
log.Error(err)
}
serverUpMetricValue = 1
//serverUpMetricValue = 1
} else {
log.Warnf("Health check still failing. Backend: %q URL: %q Reason: %s", backend.name, disableURL.String(), err)
newDisabledURLs = append(newDisabledURLs, disableURL)
}
labelValues := []string{"backend", backend.name, "url", disableURL.String()}
hc.metrics.BackendServerUpGauge().With(labelValues...).Set(serverUpMetricValue)
//labelValues := []string{"backend", backend.name, "url", disableURL.String()}
//hc.metrics.BackendServerUpGauge().With(labelValues...).Set(serverUpMetricValue)
}
backend.disabledURLs = newDisabledURLs
// FIXME re enable metrics
for _, enableURL := range enabledURLs {
serverUpMetricValue := float64(1)
//serverUpMetricValue := float64(1)
if err := checkHealth(enableURL, backend); err != nil {
log.Warnf("Health check failed: Remove from server list. Backend: %q URL: %q Reason: %s", backend.name, enableURL.String(), err)
if err := backend.LB.RemoveServer(enableURL); err != nil {
log.Error(err)
}
backend.disabledURLs = append(backend.disabledURLs, enableURL)
serverUpMetricValue = 0
//serverUpMetricValue = 0
}
labelValues := []string{"backend", backend.name, "url", enableURL.String()}
hc.metrics.BackendServerUpGauge().With(labelValues...).Set(serverUpMetricValue)
//labelValues := []string{"backend", backend.name, "url", enableURL.String()}
//hc.metrics.BackendServerUpGauge().With(labelValues...).Set(serverUpMetricValue)
}
}
// FIXME re add metrics
//func GetHealthCheck(metrics metricsRegistry) *HealthCheck {
// GetHealthCheck returns the health check which is guaranteed to be a singleton.
func GetHealthCheck(metrics metricsRegistry) *HealthCheck {
func GetHealthCheck() *HealthCheck {
once.Do(func() {
singleton = newHealthCheck(metrics)
singleton = newHealthCheck()
//singleton = newHealthCheck(metrics)
})
return singleton
}
func newHealthCheck(metrics metricsRegistry) *HealthCheck {
// FIXME re add metrics
//func newHealthCheck(metrics metricsRegistry) *HealthCheck {
func newHealthCheck() *HealthCheck {
return &HealthCheck{
Backends: make(map[string]*BackendConfig),
metrics: metrics,
//metrics: metrics,
}
}

View file

@ -146,7 +146,8 @@ func TestSetBackendsConfiguration(t *testing.T) {
assert.Equal(t, test.expectedNumRemovedServers, lb.numRemovedServers, "removed servers")
assert.Equal(t, test.expectedNumUpsertedServers, lb.numUpsertedServers, "upserted servers")
assert.Equal(t, test.expectedGaugeValue, collectingMetrics.Gauge.GaugeValue, "ServerUp Gauge")
// FIXME re add metrics
//assert.Equal(t, test.expectedGaugeValue, collectingMetrics.Gauge.GaugeValue, "ServerUp Gauge")
})
}
}

View file

@ -13,7 +13,7 @@ import (
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/log"
"github.com/containous/traefik/middlewares/accesslog"
"github.com/containous/traefik/old/middlewares/accesslog"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)

View file

@ -11,9 +11,9 @@ import (
"time"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/old/provider/acme"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/testhelpers"
"github.com/containous/traefik/types"
"github.com/go-check/check"
"github.com/miekg/dns"
checker "github.com/vdemeester/shakers"
@ -256,6 +256,8 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleDynamicCertificatesWithWildcard(c *check
}
func (s *AcmeSuite) TestHTTP01OnDemand(c *check.C) {
c.Skip("on demand")
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_base.toml",
template: templateModel{
@ -272,6 +274,8 @@ func (s *AcmeSuite) TestHTTP01OnDemand(c *check.C) {
}
func (s *AcmeSuite) TestHTTP01OnDemandStaticCertificatesWithWildcard(c *check.C) {
c.Skip("on demand")
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_tls.toml",
template: templateModel{
@ -288,6 +292,8 @@ func (s *AcmeSuite) TestHTTP01OnDemandStaticCertificatesWithWildcard(c *check.C)
}
func (s *AcmeSuite) TestHTTP01OnDemandStaticCertificatesWithWildcardMultipleEntrypoints(c *check.C) {
c.Skip("on demand")
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_tls_multiple_entrypoints.toml",
template: templateModel{
@ -304,6 +310,8 @@ func (s *AcmeSuite) TestHTTP01OnDemandStaticCertificatesWithWildcardMultipleEntr
}
func (s *AcmeSuite) TestHTTP01OnDemandDynamicCertificatesWithWildcard(c *check.C) {
c.Skip("on demand")
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_tls_dynamic.toml",
template: templateModel{

View file

@ -7,7 +7,7 @@ import (
"time"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/old/provider/label"
"github.com/go-check/check"
"github.com/hashicorp/consul/api"
checker "github.com/vdemeester/shakers"

View file

@ -16,7 +16,7 @@ import (
"github.com/containous/staert"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/types"
"github.com/containous/traefik/old/types"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)

View file

@ -8,8 +8,8 @@ import (
"time"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/old/types"
"github.com/containous/traefik/testhelpers"
"github.com/containous/traefik/types"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)

View file

@ -10,7 +10,7 @@ import (
"time"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/old/provider/label"
"github.com/docker/docker/pkg/namesgenerator"
"github.com/go-check/check"
d "github.com/libkermit/docker"

View file

@ -11,7 +11,7 @@ import (
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/types"
"github.com/containous/traefik/old/types"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)

View file

@ -24,7 +24,7 @@ func (s *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
fakeDNS = "127.0.0.1"
}
for _, q := range r.Question {
log.Printf("Query -- [%s] %s", q.Name, dns.TypeToString[q.Qtype])
log.Infof("Query -- [%s] %s", q.Name, dns.TypeToString[q.Qtype])
switch q.Qtype {
case dns.TypeA:

View file

@ -40,14 +40,14 @@ defaultEntryPoints = ["http", "https"]
[file]
[backends]
[backends.backend]
[backends.backend.servers.server1]
[services]
[services.test.loadbalancer]
[[services.test.loadbalancer.servers]]
url = "http://127.0.0.1:9010"
weight = 1
[frontends]
[frontends.frontend]
backend = "backend"
[frontends.frontend.routes.test]
rule = "Host:traefik.acme.wtf"
[routers]
[routers.test]
service = "test"
rule = "Host:traefik.acme.wtf"
entryPoints = ["https"]

View file

@ -37,14 +37,14 @@ path="/traefik"
[file]
[backends]
[backends.backend]
[backends.backend.servers.server1]
[services]
[services.test.loadbalancer]
[[services.test.loadbalancer.servers]]
url = "http://127.0.0.1:9010"
weight = 1
[frontends]
[frontends.frontend]
backend = "backend"
[frontends.frontend.routes.test]
rule = "Host:traefik.acme.wtf"
[routers]
[routers.test]
service = "test"
rule = "Host:traefik.acme.wtf"
entryPoints = ["https"]

View file

@ -43,14 +43,14 @@ defaultEntryPoints = ["http", "https"]
[file]
[backends]
[backends.backend]
[backends.backend.servers.server1]
[services]
[services.test.loadbalancer]
[[services.test.loadbalancer.servers]]
url = "http://127.0.0.1:9010"
weight = 1
[frontends]
[frontends.frontend]
backend = "backend"
[frontends.frontend.routes.test]
rule = "Host:traefik.acme.wtf"
[routers]
[routers.test]
service = "test"
rule = "Host:traefik.acme.wtf"
entryPoints = ["https"]

View file

@ -43,17 +43,3 @@ defaultEntryPoints = ["http", "https"]
{{end}}
[api]
[file]
[backends]
[backends.backend]
[backends.backend.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[frontends]
[frontends.frontend]
backend = "backend"
[frontends.frontend.routes.test]
rule = "Host:traefik.acme.wtf"

View file

@ -1,14 +1,15 @@
[backends]
[backends.backend]
[backends.backend.servers.server1]
[services]
[services.test.loadbalancer]
[[services.test.loadbalancer.servers]]
url = "http://127.0.0.1:9010"
weight = 1
[frontends]
[frontends.frontend]
backend = "backend"
[frontends.frontend.routes.test]
rule = "Host:traefik.acme.wtf"
[routers]
[routers.test]
service = "test"
rule = "Host:traefik.acme.wtf"
entryPoints = ["https"]
[[tls]]
entryPoints = ["https"]

View file

@ -7,24 +7,29 @@ logLevel = "DEBUG"
address = ":8080"
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:8989474"
weight = 1
[backends.error]
[backends.error.servers.error]
url = "http://{{.Server2}}:80"
weight = 1
[frontends]
[frontends.frontend1]
passHostHeader = true
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:test.local"
[frontends.frontend1.errors]
[frontends.frontend1.errors.networks]
status = ["500-502", "503-599"]
backend = "error"
query = "/50x.html"
[routers]
[routers.router1]
middlewares = ["error"]
service = "service1"
[routers.router1.routes.test_1]
rule = "Host:test.local"
[middlewares]
[middlewares.error.errors]
status = ["500-502", "503-599"]
service = "error"
query = "/50x.html"
[services]
[services.service1.loadbalancer]
passHostHeader = true
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server1}}:8989474"
weight = 1
[services.error.loadbalancer]
[[services.error.loadbalancer.servers]]
url = "http://{{.Server2}}:80"
weight = 1

View file

@ -7,24 +7,29 @@ logLevel = "DEBUG"
address = ":8080"
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
weight = 1
[backends.error]
[backends.error.servers.error]
url = "http://{{.Server2}}:80"
weight = 1
[frontends]
[frontends.frontend1]
passHostHeader = true
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:test.local"
[frontends.frontend1.errors]
[frontends.frontend1.errors.networks]
status = ["500-502", "503-599"]
backend = "error"
query = "/50x.html"
[routers]
[routers.router1]
middlewares = ["error"]
service = "service1"
[routers.router1.routes.test_1]
rule = "Host:test.local"
[middlewares]
[middlewares.error.errors]
status = ["500-502", "503-599"]
service = "error"
query = "/50x.html"
[services]
[services.service1.loadbalancer]
passHostHeader = true
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server1}}:80"
weight = 1
[services.error.loadbalancer]
[[services.error.loadbalancer.servers]]
url = "http://{{.Server2}}:80"
weight = 1

View file

@ -1,12 +1,10 @@
# rules
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://172.17.0.2:80"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
rule = "Path:/test1"
service = "service1"
[services]
[services.service1.loadbalancer]
[[services.service1.loadbalancer.servers]]
url = "http://172.17.0.2:80"
weight = 1

View file

@ -1,12 +1,10 @@
# rules
[backends]
[backends.backend2]
[backends.backend2.servers.server1]
url = "http://172.17.0.123:80"
weight = 1
[frontends]
[frontends.frontend2]
backend = "backend2"
[frontends.frontend2.routes.test_2]
[routers]
[routers.router2]
rule = "Path:/test2"
service = "service2"
[services]
[services.service2.loadbalancer]
[[services.service2.loadbalancer.servers]]
url = "http://172.17.0.123:80"
weight = 1

View file

@ -2,39 +2,41 @@ defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
address = ":8000"
address = ":8000"
logLevel = "DEBUG"
[file]
# rules
[backends]
[backends.backend1]
[backends.backend1.circuitbreaker]
expression = "NetworkErrorRatio() > 0.5"
[backends.backend1.servers.server1]
url = "http://172.17.0.2:80"
weight = 10
[backends.backend1.servers.server2]
url = "http://172.17.0.3:80"
weight = 1
[backends.backend2]
[backends.backend2.LoadBalancer]
method = "drr"
[backends.backend2.servers.server1]
url = "http://172.17.0.4:80"
weight = 1
[backends.backend2.servers.server2]
url = "http://172.17.0.5:80"
weight = 2
[frontends]
[frontends.frontend1]
backend = "backend2"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
rule = "Host:test.localhost"
[frontends.frontend2]
backend = "backend1"
[frontends.frontend2.routes.test_2]
service = "service2"
[routers.router2]
rule = "Path:/test"
middlewares = ["circuitbreaker"]
service = "service1"
[middlewares]
[middlewares.circuitbreaker.circuitbreaker]
expression = "NetworkErrorRatio() > 0.5"
[services]
[services.service1.loadbalancer]
[[services.service1.loadbalancer.servers]]
url = "http://172.17.0.2:80"
weight = 10
[[services.service1.loadbalancer.servers]]
url = "http://172.17.0.3:80"
weight = 1
[services.service2]
[services.service2.loadbalancer]
method = "drr"
[[services.service2.loadbalancer.servers]]
url = "http://172.17.0.4:80"
weight = 1
[[services.service2.loadbalancer.servers]]
url = "http://172.17.0.5:80"
weight = 2

View file

@ -2,28 +2,27 @@ defaultEntryPoints = ["https"]
rootCAs = [ """{{ .CertContent }}""" ]
debug = true
[entryPoints]
[entryPoints.https]
address = ":4443"
address = ":4443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}"""
certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}"""
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
rule = "Host:127.0.0.1"
service = "service1"
[services]
[services.service1.loadbalancer]
[[services.service1.loadbalancer.servers]]
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1

View file

@ -1,24 +1,22 @@
defaultEntryPoints = ["http"]
debug=true
debug = true
[entryPoints]
[entryPoints.http]
address = ":8081"
address = ":8081"
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "h2c://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
rule = "Host:127.0.0.1"
service = "service1"
[services]
[services.service1.loadbalancer]
[[services.service1.loadbalancer.servers]]
url = "h2c://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1

View file

@ -1,25 +1,26 @@
defaultEntryPoints = ["https"]
debug = true
[entryPoints]
[entryPoints.https]
address = ":4443"
address = ":4443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}"""
certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}"""
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
[routers]
[routers.router1]
rule = "Host:127.0.0.1"
service = "service1"
[services]
[services.service1.loadbalancer]
[[services.service1.loadbalancer.servers]]
url = "h2c://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:127.0.0.1"

View file

@ -2,28 +2,29 @@ defaultEntryPoints = ["https"]
insecureSkipVerify = true
debug = true
[entryPoints]
[entryPoints.https]
address = ":4443"
address = ":4443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}"""
certFile = """{{ .CertContent }}"""
keyFile = """{{ .KeyContent }}"""
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
rule = "Host:127.0.0.1"
service = "service1"
[services]
[services.service1.loadbalancer]
[[services.service1.loadbalancer.servers]]
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1

View file

@ -15,17 +15,15 @@ rootCAs = [ """{{ .CertContent }}""" ]
[file]
[backends]
[backends.backend1]
[backends.backend1.responseForwarding]
flushInterval="1ms"
[backends.backend1.servers.server1]
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
rule = "Host:127.0.0.1"
service = "service1"
[services]
[services.service1.loadbalancer]
[services.service1.loadbalancer.responseForwarding]
flushInterval="1ms"
[[services.service1.loadbalancer.servers]]
url = "https://127.0.0.1:{{ .GRPCServerPort }}"
weight = 1

View file

@ -4,30 +4,28 @@ logLevel = "DEBUG"
[entryPoints]
[entryPoints.http1]
address = ":8000"
address = ":8000"
[entryPoints.http2]
address = ":9000"
address = ":9000"
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.LoadBalancer]
method = "drr"
[backends.backend1.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
weight = 1
[backends.backend1.servers.server2]
url = "http://{{.Server2}}:80"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
service = "service1"
rule = "Host:test.localhost"
[services]
[services.service1.loadbalancer]
method = "drr"
[services.service1.loadbalancer.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server1}}:80"
weight = 1
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server2}}:80"
weight = 1

View file

@ -4,30 +4,29 @@ logLevel = "DEBUG"
[entryPoints]
[entryPoints.http1]
address = ":8000"
address = ":8000"
[entryPoints.http2]
address = ":9000"
address = ":9000"
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.LoadBalancer]
method = "wrr"
[backends.backend1.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
weight = 1
[backends.backend1.servers.server2]
url = "http://{{.Server2}}:80"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
service = "service1"
rule = "Host:test.localhost"
[services]
[services.service1.loadbalancer]
method = "wrr"
[services.service1.loadbalancer.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server1}}:80"
weight = 1
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server2}}:80"
weight = 1

View file

@ -4,24 +4,25 @@ logLevel = "DEBUG"
[entryPoints]
[entryPoints.http]
address = ":8000"
address = ":8000"
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.healthcheck]
path = "/health"
port = 80
interval = "1s"
timeout = "0.9s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:81"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
service = "service1"
rule = "Host:test.localhost"
[services]
[services.service1.loadbalancer]
method = "drr"
[services.service1.loadbalancer.healthcheck]
path = "/health"
port = 80
interval = "1s"
timeout = "0.9s"
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server1}}:81"
weight = 1

View file

@ -4,26 +4,26 @@ logLevel = "DEBUG"
[entryPoints]
[entryPoints.http]
address = ":8000"
address = ":8000"
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
weight = 1
[backends.backend1.servers.server2]
url = "http://{{.Server2}}:80"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
[routers]
[routers.router1]
service = "service1"
rule = "Host:test.localhost"
[services]
[services.service1.loadbalancer]
[services.service1.loadbalancer.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server1}}:80"
weight = 1
[[services.service1.loadbalancer.servers]]
url = "http://{{.Server2}}:80"
weight = 1

View file

@ -20,22 +20,24 @@ defaultEntryPoints = ["https"]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[backends.backend2]
[backends.backend2.servers.server1]
url = "http://127.0.0.1:9020"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Host:snitest.com"
[Routers.router2]
Service = "service2"
Rule = "Host:snitest.org"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[frontends.frontend2]
backend = "backend2"
[frontends.frontend2.routes.test_2]
rule = "Host:snitest.org"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
Weight = 1
[Services.service2]
[Services.service2.LoadBalancer]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
Weight = 1

View file

@ -19,22 +19,24 @@ defaultEntryPoints = ["https"]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[backends.backend2]
[backends.backend2.servers.server1]
url = "http://127.0.0.1:9020"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Host:snitest.com"
[Routers.router2]
Service = "service2"
Rule = "Host:snitest.org"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[frontends.frontend2]
backend = "backend2"
[frontends.frontend2.routes.test_2]
rule = "Host:snitest.org"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
Weight = 1
[Services.service2]
[Services.service2.LoadBalancer]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
Weight = 1

View file

@ -19,23 +19,24 @@ defaultEntryPoints = ["https"]
[api]
[file]
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Host:snitest.com"
[Routers.router2]
Service = "service2"
Rule = "Host:snitest.org"
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[backends.backend2]
[backends.backend2.servers.server1]
url = "http://127.0.0.1:9020"
weight = 1
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[frontends.frontend2]
backend = "backend2"
[frontends.frontend2.routes.test_2]
rule = "Host:snitest.org"
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
Weight = 1
[Services.service2]
[Services.service2.LoadBalancer]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
Weight = 1

View file

@ -1,22 +1,24 @@
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[backends.backend2]
[backends.backend2.servers.server1]
url = "http://127.0.0.1:9020"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Host:snitest.com"
[Routers.router2]
Service = "service2"
Rule = "Host:snitest.org"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[frontends.frontend2]
backend = "backend2"
[frontends.frontend2.routes.test_2]
rule = "Host:snitest.org"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
Weight = 1
[Services.service2]
[Services.service2.LoadBalancer]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
Weight = 1
[[tls]]
entryPoints = ["https"]

View file

@ -6,6 +6,7 @@ defaultEntryPoints = ["https"]
[entryPoints.https]
address = ":4443"
[entryPoints.https.tls]
[entryPoints.https02]
address = ":8443"
[entryPoints.https02.tls]

View file

@ -14,21 +14,21 @@ defaultEntryPoints = ["https"]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Host:snitest.com"
[Routers.router2]
Service = "service1"
Rule = "Host:www.snitest.com"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[frontends.frontend2]
backend = "backend1"
[frontends.frontend2.routes.test_1]
rule = "Host:www.snitest.com"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
Weight = 1
[[tls]]
entryPoints = ["https"]

View file

@ -5,8 +5,10 @@ defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
address = ":8888"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":8443"
[entryPoints.https.tls]
@ -15,56 +17,88 @@ defaultEntryPoints = ["http", "https"]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:80"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Middlewares = ["redirect-https"]
Rule = "Host: example.com"
[frontends]
[Routers.router2]
Service = "service1"
Middlewares = ["redirect-https", "api-slash-strip"]
Rule = "Host: example2.com"
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host: example.com; PathPrefixStrip: /api"
[frontends.frontend2]
backend = "backend1"
[frontends.frontend2.routes.test_1]
rule = "Host: example2.com; PathPrefixStrip: /api/"
[Routers.router3]
Service = "service1"
Middlewares = ["redirect-https", "foo-add-prefix"]
Rule = "Host: test.com"
[frontends.frontend3]
backend = "backend1"
[frontends.frontend3.routes.test_1]
rule = "Host: test.com; AddPrefix: /foo"
[frontends.frontend4]
backend = "backend1"
[frontends.frontend4.routes.test_1]
rule = "Host: test2.com; AddPrefix: /foo/"
[Routers.router4]
Service = "service1"
Middlewares = ["redirect-https", "foo-slash-add-prefix"]
Rule = "Host: test2.com"
[frontends.frontend5]
backend = "backend1"
[frontends.frontend5.routes.test_1]
rule = "Host: foo.com; PathPrefixStripRegex: /{id:[a-z]+}"
[frontends.frontend6]
backend = "backend1"
[frontends.frontend6.routes.test_1]
rule = "Host: foo2.com; PathPrefixStripRegex: /{id:[a-z]+}/"
[Routers.router5]
Service = "service1"
Middlewares = ["redirect-https", "id-strip-regex-prefix"]
Rule = "Host: foo.com"
[frontends.frontend7]
backend = "backend1"
[frontends.frontend7.routes.test_1]
rule = "Host: bar.com; ReplacePathRegex: /api /"
[frontends.frontend8]
backend = "backend1"
[frontends.frontend8.routes.test_1]
rule = "Host: bar2.com; ReplacePathRegex: /api/ /"
[Routers.router6]
Service = "service1"
Middlewares = ["redirect-https", "id-slash-strip-regex-prefix"]
Rule = "Host: foo2.com"
[frontends.frontend9]
backend = "backend1"
[frontends.frontend9.routes.test_1]
rule = "Host: pow.com; ReplacePath: /api"
[frontends.frontend10]
backend = "backend1"
[frontends.frontend10.routes.test_1]
rule = "Host: pow2.com; ReplacePath: /api/"
[Routers.router7]
Service = "service1"
Middlewares = ["redirect-https", "api-regex-replace"]
Rule = "Host: bar.com"
[Routers.router8]
Service = "service1"
Middlewares = ["redirect-https", "api-slash-regex-replace"]
Rule = "Host: bar2.com"
[Routers.router9]
Service = "service1"
Middlewares = ["redirect-https", "api-replace-path"]
Rule = "Host: pow.com"
[Routers.router10]
Service = "service1"
Middlewares = ["redirect-https", "api-slash-replace-path"]
Rule = "Host: pow2.com"
[Middlewares]
[Middlewares.api-strip.StripPrefix]
prefixes = ["/api"]
[Middlewares.api-slash-strip.StripPrefix]
prefixes = ["/api/"]
[Middlewares.foo-add-prefix.AddPrefix]
prefix = "/foo"
[Middlewares.foo-slash-add-prefix.AddPrefix]
prefix = "/foo/"
[Middlewares.id-strip-regex-prefix.StripPrefixRegex]
regex = ["/{id:[a-z]+}"]
[Middlewares.id-slash-strip-regex-prefix.StripPrefixRegex]
regex = ["/{id:[a-z]+}/"]
[Middlewares.api-regex-replace.ReplacePathRegex]
regex = "/api"
replacement = "/"
[Middlewares.api-slash-regex-replace.ReplacePathRegex]
regex = "/api/"
replacement = "/"
[Middlewares.api-replace-path.ReplacePath]
path = "/api"
[Middlewares.api-slash-replace-path.ReplacePath]
path = "/api/"
[Middlewares.redirect-https.redirect]
regex = "^(?:https?://)?([\\w\\._-]+)(?::\\d+)?(.*)$"
replacement = "https://${1}:8443${2}"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:80"
Weight = 1

View file

@ -17,22 +17,24 @@ defaultEntryPoints = ["https"]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[backends.backend2]
[backends.backend2.servers.server1]
url = "http://127.0.0.1:9020"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Host:snitest.com"
[Routers.router2]
Service = "service2"
Rule = "Host:snitest.org"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[frontends.frontend2]
backend = "backend2"
[frontends.frontend2.routes.test_2]
rule = "Host:snitest.org"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
Weight = 1
[Services.service2]
[Services.service2.LoadBalancer]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9020"
Weight = 1

View file

@ -20,18 +20,18 @@ defaultEntryPoints = ["https"]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Host:snitest.com"
[Routers.router2]
Service = "service1"
Rule = "Host:www.snitest.com"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[frontends.frontend2]
backend = "backend1"
[frontends.frontend2.routes.test_1]
rule = "Host:www.snitest.com"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
Weight = 1

View file

@ -15,14 +15,15 @@ defaultEntryPoints = ["https"]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:9010"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Host:snitest.com"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:snitest.com"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:9010"
Weight = 1

View file

@ -28,14 +28,15 @@ fblo6RBxUQ==
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "{{ .BackendHost }}"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Path: /ping"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path: /ping"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "{{ .BackendHost }}"
Weight = 1

View file

@ -13,14 +13,15 @@ rootCAs = [ "fixtures/https/rootcas/local.crt"]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "{{ .BackendHost }}"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Path: /ping"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path: /ping"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "{{ .BackendHost }}"
Weight = 1

View file

@ -27,14 +27,15 @@ entryPoint = "api"
################################################################
# rules
################################################################
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://127.0.0.1:8081"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Path: /test1"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path: /test1"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://127.0.0.1:8081"
Weight = 1

View file

@ -14,14 +14,15 @@ watch = true
exposedByDefault = false
[file]
[frontends]
[frontends.frontend-1]
backend = "backend-test"
[frontends.frontend-1.routes.test_1]
rule = "PathPrefix:/file"
[Routers]
[Routers.router-1]
Service = "service-test"
Rule = "PathPrefix:/file"
[backends]
[backends.backend-test]
[backends.backend-test.servers.website]
url = "http://{{ .IP }}"
weight = 1
[Services]
[Services.service-test]
[Services.service-test.LoadBalancer]
[[Services.service-test.LoadBalancer.Servers]]
URL = "http://{{ .IP }}"
Weight = 1

View file

@ -3,22 +3,23 @@ defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
address = ":8000"
address = ":8000"
[entryPoints.http.proxyProtocol]
trustedIPs = ["{{.HaproxyIP}}"]
trustedIPs = ["{{.HaproxyIP}}"]
[api]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://{{.WhoamiIP}}"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Path:/whoami"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path:/whoami"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://{{.WhoamiIP}}"
Weight = 1

View file

@ -3,22 +3,22 @@ defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
address = ":8000"
address = ":8000"
[entryPoints.http.proxyProtocol]
trustedIPs = ["1.2.3.4"]
trustedIPs = ["1.2.3.4"]
[api]
[file]
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Path:/whoami"
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://{{.WhoamiIP}}"
weight = 1
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path:/whoami"
[[Services.service1.LoadBalancer.Servers]]
URL = "http://{{.WhoamiIP}}"
Weight = 1

View file

@ -8,25 +8,29 @@ logLevel = "DEBUG"
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
weight = 1
[frontends]
[frontends.frontend1]
passHostHeader = true
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path:/"
[frontends.frontend1.ratelimit]
[Routers]
[Routers.router1]
Service = "service1"
Middlewares = [ "ratelimit" ]
Rule = "Path:/"
[Middlewares]
[Middlewares.ratelimit.RateLimit]
extractorfunc = "client.ip"
[frontends.frontend1.ratelimit.rateset.rateset1]
[Middlewares.ratelimit.RateLimit.rateset.rateset1]
period = "60s"
average = 4
burst = 5
[frontends.frontend1.ratelimit.rateset.rateset2]
[Middlewares.ratelimit.RateLimit.rateset.rateset2]
period = "3s"
average = 1
burst = 2
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
passHostHeader = true
[[Services.service1.LoadBalancer.Servers]]
URL = "http://{{.Server1}}:80"
Weight = 1

View file

@ -13,16 +13,17 @@ logLevel = "DEBUG"
requestAcceptGraceTimeout = "10s"
[file]
[backends]
[backends.backend]
[backends.backend.servers.server]
url = "{{.Server}}"
weight = 1
[Routers]
[Routers.router]
Service = "service"
Rule = "Path:/service"
[frontends]
[frontends.frontend]
backend = "backend"
[frontends.frontend.routes.service]
rule = "Path:/service"
[Services]
[Services.service]
[Services.service.LoadBalancer]
[[Services.service.LoadBalancer.Servers]]
URL = "{{.Server}}"
Weight = 1
[ping]

View file

@ -8,20 +8,25 @@ logLevel = "DEBUG"
[api]
[retry]
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "http://{{.WhoamiEndpoint}}:8080" # not valid
weight = 1
[backends.backend1.servers.server2]
url = "http://{{.WhoamiEndpoint}}:80"
weight = 1
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "PathPrefix:/"
[Routers]
[Routers.router1]
Service = "service1"
Middlewares = [ "retry" ]
Rule = "PathPrefix:/"
[Middlewares.retry.Retry]
Attempts = 3
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://{{.WhoamiEndpoint}}:8080"
Weight = 1
[[Services.service1.LoadBalancer.Servers]]
URL = "http://{{.WhoamiEndpoint}}:80"
Weight = 1

View file

@ -7,10 +7,12 @@ defaultEntryPoints = ["http"]
[entryPoints.traefik]
address = ":8001"
[entryPoints.traefik.auth.basic]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
[api]
middlewares = ["authentication"]
[middleware.authentication.basic-auth]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
[ping]

View file

@ -8,26 +8,26 @@ debug=true
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "{{ .Server1 }}"
weight = 1
[Routers]
[Routers.router1]
EntryPoints = ["http"]
Service = "service1"
Rule = "PathPrefix:/whoami"
[backends.backend2]
[backends.backend2.servers.server1]
url = "{{ .Server2 }}"
weight = 1
[Routers.router2]
EntryPoints = ["traefik"]
Service = "service2"
Rule = "PathPrefix:/whoami"
[frontends]
[frontends.frontend1]
entrypoints=["http"]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "PathPrefix:/whoami"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "{{ .Server1 }}"
Weight = 1
[frontends.frontend2]
backend = "backend2"
entrypoints=["traefik"]
[frontends.frontend2.routes.test_1]
rule = "PathPrefix:/whoami"
[Services.service2]
[Services.service2.LoadBalancer]
[[Services.service2.LoadBalancer.Servers]]
URL = "{{ .Server2 }}"
Weight = 1

View file

@ -3,37 +3,37 @@ defaultEntryPoints = ["http"]
[entryPoints]
[entryPoints.http]
address = ":8000"
address = ":8000"
[accessLog]
format = "json"
format = "json"
[api]
[forwardingTimeouts]
dialTimeout = "300ms"
responseHeaderTimeout = "300ms"
dialTimeout = "300ms"
responseHeaderTimeout = "300ms"
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
# Non-routable IP address that should always deliver a dial timeout.
# See: https://stackoverflow.com/questions/100841/artificially-create-a-connection-timeout-error#answer-904609
url = "http://50.255.255.1"
weight = 1
[backends.backend2]
[backends.backend2.servers.server2]
url = "http://{{.TimeoutEndpoint}}:9000"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Path:/dialTimeout"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Path:/dialTimeout"
[frontends.frontend2]
backend = "backend2"
[frontends.frontend2.routes.test_2]
rule = "Path:/responseHeaderTimeout"
[Routers.router2]
Service = "service2"
Rule = "Path:/responseHeaderTimeout"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
[[Services.service1.LoadBalancer.Servers]]
URL = "http://50.255.255.1"
Weight = 1
[Services.service2]
[Services.service2.LoadBalancer]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://{{.TimeoutEndpoint}}:9000"
Weight = 1

View file

@ -19,53 +19,57 @@ debug = true
samplingType = "const"
samplingParam = 1.0
[retry]
attempts = 3
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server-ratelimit]
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
weight = 1
[backends.backend2]
[backends.backend2.servers.server-retry]
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
weight = 1
[backends.backend3]
[backends.backend3.servers.server-auth]
url = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Middlewares = ["retry", "ratelimit"]
Rule = "Path:/ratelimit"
[Routers.router2]
Service = "service2"
Middlewares = ["retry"]
Rule = "Path:/retry"
[Routers.router3]
Service = "service3"
Middlewares = ["retry", "basic-auth"]
Rule = "Path:/auth"
[frontends]
[frontends.frontend1]
[Middlewares]
[Middlewares.retry.retry]
attempts = 3
[Middlewares.basic-auth.BasicAuth]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
[Middlewares.ratelimit.RateLimit]
extractorfunc = "client.ip"
[Middlewares.ratelimit.RateLimit.rateset.rateset1]
period = "60s"
average = 4
burst = 5
[Middlewares.ratelimit.RateLimit.rateset.rateset2]
period = "3s"
average = 1
burst = 2
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
passHostHeader = true
[[Services.service1.LoadBalancer.Servers]]
URL = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
Weight = 1
[Services.service2]
passHostHeader = true
backend = "backend1"
[frontends.frontend1.routes.test_ratelimit]
rule = "Path:/ratelimit"
[frontends.frontend1.ratelimit]
extractorfunc = "client.ip"
[frontends.frontend1.ratelimit.rateset.rateset1]
period = "60s"
average = 4
burst = 5
[frontends.frontend1.ratelimit.rateset.rateset2]
period = "3s"
average = 1
burst = 2
[frontends.frontend2]
[Services.service2.LoadBalancer]
[[Services.service2.LoadBalancer.Servers]]
URL = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
Weight = 1
[Services.service3]
passHostHeader = true
backend = "backend2"
[frontends.frontend2.routes.test_retry]
rule = "Path:/retry"
[frontends.frontend3]
passHostHeader = true
backend = "backend3"
[frontends.frontend3.auth.basic]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
[frontends.frontend3.routes.test_auth]
rule = "Path:/auth"
[Services.service3.LoadBalancer]
[[Services.service3.LoadBalancer.Servers]]
URL = "http://{{.WhoAmiIP}}:{{.WhoAmiPort}}"
Weight = 1

View file

@ -10,15 +10,15 @@ logLevel = "DEBUG"
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "{{ .WebsocketServer }}"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "PathPrefix:/ws"
[frontends]
[frontends.frontend1]
backend = "backend1"
passHostHeader = true
[frontends.frontend1.routes.test_1]
rule = "PathPrefix:/ws"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
passHostHeader = true
[[Services.service1.LoadBalancer.Servers]]
URL = "{{ .WebsocketServer }}"
Weight = 1

View file

@ -15,15 +15,15 @@ insecureSkipVerify=true
[file]
[backends]
[backends.backend1]
[backends.backend1.servers.server1]
url = "{{ .WebsocketServer }}"
weight = 1
[Routers]
[Routers.router1]
Service = "service1"
Rule = "Path:/echo,/ws"
[frontends]
[frontends.frontend1]
backend = "backend1"
passHostHeader = true
[frontends.frontend1.routes.test_1]
rule = "Path:/echo,/ws"
[Services]
[Services.service1]
[Services.service1.LoadBalancer]
PassHostHeader = true
[[Services.service1.LoadBalancer.Servers]]
URL = "{{ .WebsocketServer }}"
Weight = 1

View file

@ -167,7 +167,7 @@ func (s *GRPCSuite) TestGRPC(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
c.Assert(err, check.IsNil)
var response string
@ -205,7 +205,7 @@ func (s *GRPCSuite) TestGRPCh2c(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
c.Assert(err, check.IsNil)
var response string
@ -247,7 +247,7 @@ func (s *GRPCSuite) TestGRPCh2cTermination(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
c.Assert(err, check.IsNil)
var response string
@ -289,7 +289,7 @@ func (s *GRPCSuite) TestGRPCInsecure(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
c.Assert(err, check.IsNil)
var response string
@ -336,7 +336,7 @@ func (s *GRPCSuite) TestGRPCBuffer(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
c.Assert(err, check.IsNil)
var client helloworld.Greeter_StreamExampleClient
client, closer, err := callStreamExampleClientGRPC()
@ -364,7 +364,7 @@ func (s *GRPCSuite) TestGRPCBuffer(c *check.C) {
func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
stopStreamExample := make(chan bool)
defer func() { stopStreamExample <- true }()
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
_, port, err := net.SplitHostPort(lis.Addr().String())
@ -387,21 +387,22 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
KeyContent: string(LocalhostKey),
GRPCServerPort: port,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, check.IsNil)
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:127.0.0.1"))
c.Assert(err, check.IsNil)
var client helloworld.Greeter_StreamExampleClient
client, closer, err := callStreamExampleClientGRPC()
defer closer()
defer func() { stopStreamExample <- true }()
c.Assert(err, check.IsNil)
received := make(chan bool)
@ -412,7 +413,7 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
received <- true
}()
err = try.Do(time.Millisecond*100, func() error {
err = try.Do(100*time.Millisecond, func() error {
select {
case <-received:
return nil

View file

@ -41,7 +41,7 @@ func (s *HealthCheckSuite) TestSimpleConfiguration(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("Host:test.localhost"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 60*time.Second, try.BodyContains("Host:test.localhost"))
c.Assert(err, checker.IsNil)
frontendHealthReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/health", nil)
@ -117,7 +117,7 @@ func (s *HealthCheckSuite) doTestMultipleEntrypoints(c *check.C, fixture string)
defer cmd.Process.Kill()
// Wait for traefik
err = try.GetRequest("http://localhost:8080/api/providers", 60*time.Second, try.BodyContains("Host:test.localhost"))
err = try.GetRequest("http://localhost:8080/api/providers/file/routers", 60*time.Second, try.BodyContains("Host:test.localhost"))
c.Assert(err, checker.IsNil)
// Check entrypoint http1
@ -147,7 +147,7 @@ func (s *HealthCheckSuite) doTestMultipleEntrypoints(c *check.C, fixture string)
}
// Verify no backend service is available due to failing health checks
err = try.Request(frontendHealthReq, 3*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
err = try.Request(frontendHealthReq, 5*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
c.Assert(err, checker.IsNil)
// reactivate the whoami2
@ -194,7 +194,7 @@ func (s *HealthCheckSuite) TestPortOverload(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("Host:test.localhost"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 10*time.Second, try.BodyContains("Host:test.localhost"))
c.Assert(err, checker.IsNil)
frontendHealthReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/health", nil)

View file

@ -12,8 +12,8 @@ import (
"github.com/BurntSushi/toml"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/old/types"
traefiktls "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
@ -32,7 +32,7 @@ func (s *HTTPSSuite) TestWithSNIConfigHandshake(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -66,7 +66,7 @@ func (s *HTTPSSuite) TestWithSNIConfigRoute(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:snitest.org"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
backend1 := startTestServer("9010", http.StatusNoContent)
@ -122,7 +122,7 @@ func (s *HTTPSSuite) TestWithSNIStrictNotMatchedRequest(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -146,7 +146,7 @@ func (s *HTTPSSuite) TestWithDefaultCertificate(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -180,7 +180,7 @@ func (s *HTTPSSuite) TestWithDefaultCertificateNoSNI(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -214,7 +214,7 @@ func (s *HTTPSSuite) TestWithOverlappingStaticCertificate(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -249,7 +249,7 @@ func (s *HTTPSSuite) TestWithOverlappingDynamicCertificate(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 500*time.Millisecond, try.BodyContains("Host:snitest.com"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -282,7 +282,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -338,7 +338,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAs(c *check.
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -399,7 +399,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAsMultipleFi
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1000*time.Millisecond, try.BodyContains("Host:snitest.org"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
@ -464,7 +464,7 @@ func (s *HTTPSSuite) TestWithRootCAsContentForHTTPSOnBackend(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains(backend.URL))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 1*time.Second, try.BodyContains(backend.URL))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8081/ping", 1*time.Second, try.StatusCodeIs(http.StatusOK))
@ -486,7 +486,7 @@ func (s *HTTPSSuite) TestWithRootCAsFileForHTTPSOnBackend(c *check.C) {
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains(backend.URL))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 1*time.Second, try.BodyContains(backend.URL))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8081/ping", 1*time.Second, try.StatusCodeIs(http.StatusOK))
@ -544,7 +544,7 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithNoChange(c *check.C) {
}
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:"+tr1.TLSClientConfig.ServerName))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:"+tr1.TLSClientConfig.ServerName))
c.Assert(err, checker.IsNil)
backend1 := startTestServer("9010", http.StatusNoContent)
@ -613,7 +613,7 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithChange(c *check.C) {
}
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:"+tr2.TLSClientConfig.ServerName))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:"+tr2.TLSClientConfig.ServerName))
c.Assert(err, checker.IsNil)
backend1 := startTestServer("9010", http.StatusNoContent)
@ -676,7 +676,7 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithTlsConfigurationDeletion(c
}
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:"+tr2.TLSClientConfig.ServerName))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("Host:"+tr2.TLSClientConfig.ServerName))
c.Assert(err, checker.IsNil)
backend2 := startTestServer("9020", http.StatusResetContent)
@ -741,7 +741,7 @@ func (s *HTTPSSuite) TestEntrypointHttpsRedirectAndPathModification(c *check.C)
defer cmd.Process.Kill()
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1000*time.Millisecond, try.BodyContains("Host: example.com"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 5*time.Second, try.BodyContains("Host: example.com"))
c.Assert(err, checker.IsNil)
client := &http.Client{

View file

@ -37,29 +37,35 @@ func init() {
if *container {
// tests launched from a container
check.Suite(&AccessLogSuite{})
// FIXME Provider tests
// check.Suite(&ConsulCatalogSuite{})
// check.Suite(&ConsulSuite{})
// check.Suite(&DockerComposeSuite{})
// check.Suite(&DockerSuite{})
// check.Suite(&DynamoDBSuite{})
// check.Suite(&EurekaSuite{})
// check.Suite(&MarathonSuite{})
// check.Suite(&MarathonSuite15{})
// check.Suite(&MesosSuite{})
// FIXME use docker
// check.Suite(&AccessLogSuite{})
// check.Suite(&ConstraintSuite{})
// check.Suite(&TLSClientHeadersSuite{})
// check.Suite(&HostResolverSuite{})
// check.Suite(&LogRotationSuite{})
// FIXME e2e tests
check.Suite(&AcmeSuite{})
check.Suite(&ConstraintSuite{})
check.Suite(&ConsulCatalogSuite{})
check.Suite(&ConsulSuite{})
check.Suite(&DockerComposeSuite{})
check.Suite(&DockerSuite{})
check.Suite(&DynamoDBSuite{})
check.Suite(&ErrorPagesSuite{})
check.Suite(&EurekaSuite{})
check.Suite(&FileSuite{})
check.Suite(&GRPCSuite{})
check.Suite(&HealthCheckSuite{})
check.Suite(&HostResolverSuite{})
check.Suite(&HTTPSSuite{})
check.Suite(&LogRotationSuite{})
check.Suite(&MarathonSuite{})
check.Suite(&MarathonSuite15{})
check.Suite(&MesosSuite{})
check.Suite(&RateLimitSuite{})
check.Suite(&RetrySuite{})
check.Suite(&SimpleSuite{})
check.Suite(&TLSClientHeadersSuite{})
check.Suite(&TimeoutSuite{})
check.Suite(&TracingSuite{})
check.Suite(&WebsocketSuite{})
@ -67,7 +73,9 @@ func init() {
if *host {
// tests launched from the host
check.Suite(&ProxyProtocolSuite{})
check.Suite(&Etcd3Suite{})
// FIXME Provider tests
// check.Suite(&Etcd3Suite{})
}
}
@ -125,10 +133,10 @@ func (s *BaseSuite) traefikCmd(args ...string) (*exec.Cmd, func(*check.C)) {
func (s *BaseSuite) displayTraefikLog(c *check.C, output *bytes.Buffer) {
if output == nil || output.Len() == 0 {
log.Printf("%s: No Traefik logs.", c.TestName())
log.Infof("%s: No Traefik logs.", c.TestName())
} else {
log.Printf("%s: Traefik logs: ", c.TestName())
log.Println(output.String())
log.Infof("%s: Traefik logs: ", c.TestName())
log.Infof(output.String())
}
}

View file

@ -7,7 +7,7 @@ import (
"time"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/old/provider/label"
"github.com/gambol99/go-marathon"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"

View file

@ -7,7 +7,7 @@ import (
"time"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/old/provider/label"
"github.com/gambol99/go-marathon"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"

View file

@ -31,7 +31,7 @@ func (s *RetrySuite) TestRetry(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("PathPrefix:/"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 60*time.Second, try.BodyContains("PathPrefix:/"))
c.Assert(err, checker.IsNil)
// This simulates a DialTimeout when connecting to the backend server.
@ -53,7 +53,7 @@ func (s *RetrySuite) TestRetryWebsocket(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("PathPrefix:/"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 60*time.Second, try.BodyContains("PathPrefix:/"))
c.Assert(err, checker.IsNil)
// This simulates a DialTimeout when connecting to the backend server.

View file

@ -57,7 +57,7 @@ func (s *SimpleSuite) TestWithWebConfig(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api", 1*time.Second, try.StatusCodeIs(http.StatusOK))
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
}
@ -175,6 +175,8 @@ func (s *SimpleSuite) TestRequestAcceptGraceTimeout(c *check.C) {
}
func (s *SimpleSuite) TestApiOnSameEntryPoint(c *check.C) {
c.Skip("Use docker")
s.createComposeProject(c, "base")
s.composeProject.Start(c)
@ -193,7 +195,7 @@ func (s *SimpleSuite) TestApiOnSameEntryPoint(c *check.C) {
err = try.GetRequest("http://127.0.0.1:8000/api", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/api/providers", 1*time.Second, try.BodyContains("PathPrefix"))
err = try.GetRequest("http://127.0.0.1:8000/api/providers/file/routers", 1*time.Second, try.BodyContains("PathPrefix"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
@ -201,6 +203,8 @@ func (s *SimpleSuite) TestApiOnSameEntryPoint(c *check.C) {
}
func (s *SimpleSuite) TestStatsWithMultipleEntryPoint(c *check.C) {
c.Skip("Use docker")
s.createComposeProject(c, "stats")
s.composeProject.Start(c)
@ -221,7 +225,7 @@ func (s *SimpleSuite) TestStatsWithMultipleEntryPoint(c *check.C) {
err = try.GetRequest("http://127.0.0.1:8080/api", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("PathPrefix"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("PathPrefix"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
@ -236,6 +240,7 @@ func (s *SimpleSuite) TestStatsWithMultipleEntryPoint(c *check.C) {
}
func (s *SimpleSuite) TestNoAuthOnPing(c *check.C) {
c.Skip("Middlewares on entryPoint don't work anymore")
s.createComposeProject(c, "base")
s.composeProject.Start(c)
@ -254,6 +259,8 @@ func (s *SimpleSuite) TestNoAuthOnPing(c *check.C) {
}
func (s *SimpleSuite) TestDefaultEntrypointHTTP(c *check.C) {
c.Skip("Use docker")
s.createComposeProject(c, "base")
s.composeProject.Start(c)
@ -264,7 +271,7 @@ func (s *SimpleSuite) TestDefaultEntrypointHTTP(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("PathPrefix"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("PathPrefix"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
@ -272,6 +279,8 @@ func (s *SimpleSuite) TestDefaultEntrypointHTTP(c *check.C) {
}
func (s *SimpleSuite) TestWithUnexistingEntrypoint(c *check.C) {
c.Skip("Use docker")
s.createComposeProject(c, "base")
s.composeProject.Start(c)
@ -282,7 +291,7 @@ func (s *SimpleSuite) TestWithUnexistingEntrypoint(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("PathPrefix"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("PathPrefix"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
@ -290,6 +299,8 @@ func (s *SimpleSuite) TestWithUnexistingEntrypoint(c *check.C) {
}
func (s *SimpleSuite) TestMetricsPrometheusDefaultEntrypoint(c *check.C) {
c.Skip("Use docker")
s.createComposeProject(c, "base")
s.composeProject.Start(c)
@ -300,7 +311,7 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntrypoint(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("PathPrefix"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("PathPrefix"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
@ -311,6 +322,8 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntrypoint(c *check.C) {
}
func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) {
c.Skip("Use docker")
s.createComposeProject(c, "base")
s.composeProject.Start(c)
@ -328,7 +341,7 @@ func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("PathPrefix"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("PathPrefix"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.BodyContains(ipWhoami01))
@ -340,6 +353,8 @@ func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) {
}
func (s *SimpleSuite) TestIPStrategyWhitelist(c *check.C) {
c.Skip("Use docker")
s.createComposeProject(c, "whitelist")
s.composeProject.Start(c)
@ -350,7 +365,7 @@ func (s *SimpleSuite) TestIPStrategyWhitelist(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("override"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 1*time.Second, try.BodyContains("override"))
c.Assert(err, checker.IsNil)
testCases := []struct {
@ -416,30 +431,6 @@ func (s *SimpleSuite) TestIPStrategyWhitelist(c *check.C) {
}
}
func (s *SimpleSuite) TestDontKeepTrailingSlash(c *check.C) {
file := s.adaptFile(c, "fixtures/keep_trailing_slash.toml", struct {
KeepTrailingSlash bool
}{false})
defer os.Remove(file)
cmd, output := s.traefikCmd(withConfigFile(file))
defer output(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
oldCheckRedirect := http.DefaultClient.CheckRedirect
http.DefaultClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
err = try.GetRequest("http://127.0.0.1:8000/test/foo/", 1*time.Second, try.StatusCodeIs(http.StatusMovedPermanently))
c.Assert(err, checker.IsNil)
http.DefaultClient.CheckRedirect = oldCheckRedirect
}
func (s *SimpleSuite) TestKeepTrailingSlash(c *check.C) {
file := s.adaptFile(c, "fixtures/keep_trailing_slash.toml", struct {
KeepTrailingSlash bool

View file

@ -30,7 +30,7 @@ func (s *TimeoutSuite) TestForwardingTimeouts(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("Path:/dialTimeout"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/routers", 60*time.Second, try.BodyContains("Path:/dialTimeout"))
c.Assert(err, checker.IsNil)
// This simulates a DialTimeout when connecting to the backend server.

View file

@ -85,7 +85,7 @@ func (s *TracingSuite) TestZipkinRateLimit(c *check.C) {
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.ZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward frontend1/backend1", "rate limit"))
err = try.GetRequest("http://"+s.ZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service1/router1", "ratelimit"))
c.Assert(err, checker.IsNil)
}
@ -109,7 +109,7 @@ func (s *TracingSuite) TestZipkinRetry(c *check.C) {
err = try.GetRequest("http://127.0.0.1:8000/retry", 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.ZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward frontend2/backend2", "retry"))
err = try.GetRequest("http://"+s.ZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service2/router2", "retry"))
c.Assert(err, checker.IsNil)
}
@ -132,6 +132,6 @@ func (s *TracingSuite) TestZipkinAuth(c *check.C) {
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.ZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("entrypoint http", "auth basic"))
err = try.GetRequest("http://"+s.ZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("entrypoint http", "basic-auth"))
c.Assert(err, checker.IsNil)
}

View file

@ -57,7 +57,7 @@ func (s *WebsocketSuite) TestBase(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
conn, _, err := gorillawebsocket.DefaultDialer.Dial("ws://127.0.0.1:8000/ws", nil)
@ -107,7 +107,7 @@ func (s *WebsocketSuite) TestWrongOrigin(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:800")
@ -157,7 +157,7 @@ func (s *WebsocketSuite) TestOrigin(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:8000")
@ -218,7 +218,7 @@ func (s *WebsocketSuite) TestWrongOriginIgnoredByServer(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:80")
@ -276,7 +276,7 @@ func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
// Add client self-signed cert
@ -339,7 +339,7 @@ func (s *WebsocketSuite) TestBasicAuth(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:8000")
@ -383,7 +383,7 @@ func (s *WebsocketSuite) TestSpecificResponseFromBackend(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
_, resp, err := gorillawebsocket.DefaultDialer.Dial("ws://127.0.0.1:8000/ws", nil)
@ -429,7 +429,7 @@ func (s *WebsocketSuite) TestURLWithURLEncodedChar(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
conn, _, err := gorillawebsocket.DefaultDialer.Dial("ws://127.0.0.1:8000/ws/http%3A%2F%2Ftest", nil)
@ -484,7 +484,7 @@ func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
// Add client self-signed cert
@ -543,7 +543,7 @@ func (s *WebsocketSuite) TestHeaderAreForwared(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1"))
err = try.GetRequest("http://127.0.0.1:8080/api/providers/file/services", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
headers := http.Header{}

80
log/deprecated.go Normal file
View file

@ -0,0 +1,80 @@
package log
import "github.com/sirupsen/logrus"
// Debug logs a message at level Debug on the standard logger.
// Deprecated
func Debug(args ...interface{}) {
mainLogger.Debug(args...)
}
// Debugf logs a message at level Debug on the standard logger.
// Deprecated
func Debugf(format string, args ...interface{}) {
mainLogger.Debugf(format, args...)
}
// Info logs a message at level Info on the standard logger.
// Deprecated
func Info(args ...interface{}) {
mainLogger.Info(args...)
}
// Infof logs a message at level Info on the standard logger.
// Deprecated
func Infof(format string, args ...interface{}) {
mainLogger.Infof(format, args...)
}
// Warn logs a message at level Warn on the standard logger.
// Deprecated
func Warn(args ...interface{}) {
mainLogger.Warn(args...)
}
// Warnf logs a message at level Warn on the standard logger.
// Deprecated
func Warnf(format string, args ...interface{}) {
mainLogger.Warnf(format, args...)
}
// Error logs a message at level Error on the standard logger.
// Deprecated
func Error(args ...interface{}) {
mainLogger.Error(args...)
}
// Errorf logs a message at level Error on the standard logger.
// Deprecated
func Errorf(format string, args ...interface{}) {
mainLogger.Errorf(format, args...)
}
// Panic logs a message at level Panic on the standard logger.
// Deprecated
func Panic(args ...interface{}) {
mainLogger.Panic(args...)
}
// Panicf logs a message at level Panic on the standard logger.
// Deprecated
func Panicf(format string, args ...interface{}) {
mainLogger.Panicf(format, args...)
}
// Fatal logs a message at level Fatal on the standard logger.
// Deprecated
func Fatal(args ...interface{}) {
mainLogger.Fatal(args...)
}
// Fatalf logs a message at level Fatal on the standard logger.
// Deprecated
func Fatalf(format string, args ...interface{}) {
mainLogger.Fatalf(format, args...)
}
// AddHook adds a hook to the standard logger hooks.
func AddHook(hook logrus.Hook) {
logrus.AddHook(hook)
}

14
log/fields.go Normal file
View file

@ -0,0 +1,14 @@
package log
// Log entry name
const (
EntryPointName = "entryPointName"
RouterName = "routerName"
MiddlewareName = "middlewareName"
MiddlewareType = "middlewareType"
ProviderName = "providerName"
ServiceName = "serviceName"
MetricsProviderName = "metricsProviderName"
TracingProviderName = "tracingProviderName"
ServerName = "serverName"
)

145
log/log.go Normal file
View file

@ -0,0 +1,145 @@
package log
import (
"context"
"fmt"
"io"
"os"
"github.com/sirupsen/logrus"
)
type contextKey int
const (
loggerKey contextKey = iota
)
// Logger the Traefik logger
type Logger interface {
logrus.FieldLogger
WriterLevel(logrus.Level) *io.PipeWriter
}
var (
mainLogger Logger
logFilePath string
logFile *os.File
)
func init() {
mainLogger = logrus.StandardLogger()
logrus.SetOutput(os.Stdout)
}
// SetLogger sets the logger.
func SetLogger(l Logger) {
mainLogger = l
}
// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
logrus.SetOutput(out)
}
// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter logrus.Formatter) {
logrus.SetFormatter(formatter)
}
// SetLevel sets the standard logger level.
func SetLevel(level logrus.Level) {
logrus.SetLevel(level)
}
// GetLevel returns the standard logger level.
func GetLevel() logrus.Level {
return logrus.GetLevel()
}
// Str adds a string field
func Str(key, value string) func(logrus.Fields) {
return func(fields logrus.Fields) {
fields[key] = value
}
}
// With Adds fields
func With(ctx context.Context, opts ...func(logrus.Fields)) context.Context {
logger := FromContext(ctx)
fields := make(logrus.Fields)
for _, opt := range opts {
opt(fields)
}
logger = logger.WithFields(fields)
return context.WithValue(ctx, loggerKey, logger)
}
// FromContext Gets the logger from context
func FromContext(ctx context.Context) Logger {
if ctx == nil {
panic("nil context")
}
logger, ok := ctx.Value(loggerKey).(Logger)
if !ok {
logger = mainLogger
}
return logger
}
// WithoutContext Gets the main logger
func WithoutContext() Logger {
return mainLogger
}
// OpenFile opens the log file using the specified path
func OpenFile(path string) error {
logFilePath = path
var err error
logFile, err = os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return err
}
SetOutput(logFile)
return nil
}
// CloseFile closes the log and sets the Output to stdout
func CloseFile() error {
logrus.SetOutput(os.Stdout)
if logFile != nil {
return logFile.Close()
}
return nil
}
// RotateFile closes and reopens the log file to allow for rotation
// by an external source. If the log isn't backed by a file then
// it does nothing.
func RotateFile() error {
logger := FromContext(context.Background())
if logFile == nil && logFilePath == "" {
logger.Debug("Traefik log is not writing to a file, ignoring rotate request")
return nil
}
if logFile != nil {
defer func(f *os.File) {
_ = f.Close()
}(logFile)
}
if err := OpenFile(logFilePath); err != nil {
return fmt.Errorf("error opening log file: %s", err)
}
return nil
}

58
log/log_test.go Normal file
View file

@ -0,0 +1,58 @@
package log
import (
"bytes"
"context"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestLog(t *testing.T) {
testCases := []struct {
desc string
fields map[string]string
expected string
}{
{
desc: "Log with one field",
fields: map[string]string{
"foo": "bar",
},
expected: ` level=error msg="message test" foo=bar$`,
},
{
desc: "Log with two fields",
fields: map[string]string{
"foo": "bar",
"oof": "rab",
},
expected: ` level=error msg="message test" foo=bar oof=rab$`,
},
{
desc: "Log without field",
fields: map[string]string{},
expected: ` level=error msg="message test"$`,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
var buffer bytes.Buffer
SetOutput(&buffer)
ctx := context.Background()
for key, value := range test.fields {
ctx = With(ctx, Str(key, value))
}
FromContext(ctx).Error("message test")
assert.Regexp(t, test.expected, strings.TrimSpace(buffer.String()))
})
}
}

View file

@ -1,6 +1,7 @@
package metrics
import (
"context"
"time"
"github.com/containous/traefik/log"
@ -11,7 +12,7 @@ import (
)
var datadogClient = dogstatsd.New("traefik.", kitlog.LoggerFunc(func(keyvals ...interface{}) error {
log.Info(keyvals)
log.WithoutContext().WithField(log.MetricsProviderName, "datadog").Info(keyvals)
return nil
}))
@ -34,9 +35,9 @@ const (
)
// RegisterDatadog registers the metrics pusher if this didn't happen yet and creates a datadog Registry instance.
func RegisterDatadog(config *types.Datadog) Registry {
func RegisterDatadog(ctx context.Context, config *types.Datadog) Registry {
if datadogTicker == nil {
datadogTicker = initDatadogClient(config)
datadogTicker = initDatadogClient(ctx, config)
}
registry := &standardRegistry{
@ -58,14 +59,14 @@ func RegisterDatadog(config *types.Datadog) Registry {
return registry
}
func initDatadogClient(config *types.Datadog) *time.Ticker {
func initDatadogClient(ctx context.Context, config *types.Datadog) *time.Ticker {
address := config.Address
if len(address) == 0 {
address = "localhost:8125"
}
pushInterval, err := time.ParseDuration(config.PushInterval)
if err != nil {
log.Warnf("Unable to parse %s into pushInterval, using 10s as default value", config.PushInterval)
log.FromContext(ctx).Warnf("Unable to parse %s from config.PushInterval: using 10s as the default value", config.PushInterval)
pushInterval = 10 * time.Second
}

View file

@ -1,6 +1,7 @@
package metrics
import (
"context"
"net/http"
"strconv"
"testing"
@ -15,7 +16,7 @@ func TestDatadog(t *testing.T) {
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second
datadogRegistry := RegisterDatadog(&types.Datadog{Address: ":18125", PushInterval: "1s"})
datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Address: ":18125", PushInterval: "1s"})
defer StopDatadog()
if !datadogRegistry.IsEnabled() {

View file

@ -2,6 +2,7 @@ package metrics
import (
"bytes"
"context"
"fmt"
"net/url"
"regexp"
@ -39,13 +40,18 @@ const (
influxDBServerUpName = "traefik.backend.server.up"
)
const (
protocolHTTP = "http"
protocolUDP = "udp"
)
// RegisterInfluxDB registers the metrics pusher if this didn't happen yet and creates a InfluxDB Registry instance.
func RegisterInfluxDB(config *types.InfluxDB) Registry {
func RegisterInfluxDB(ctx context.Context, config *types.InfluxDB) Registry {
if influxDBClient == nil {
influxDBClient = initInfluxDBClient(config)
influxDBClient = initInfluxDBClient(ctx, config)
}
if influxDBTicker == nil {
influxDBTicker = initInfluxDBTicker(config)
influxDBTicker = initInfluxDBTicker(ctx, config)
}
return &standardRegistry{
@ -66,30 +72,32 @@ func RegisterInfluxDB(config *types.InfluxDB) Registry {
}
// initInfluxDBTicker creates a influxDBClient
func initInfluxDBClient(config *types.InfluxDB) *influx.Influx {
func initInfluxDBClient(ctx context.Context, config *types.InfluxDB) *influx.Influx {
logger := log.FromContext(ctx)
// TODO deprecated: move this switch into configuration.SetEffectiveConfiguration when web provider will be removed.
switch config.Protocol {
case "udp":
case protocolUDP:
if len(config.Database) > 0 || len(config.RetentionPolicy) > 0 {
log.Warn("Database and RetentionPolicy are only used when protocol is http.")
logger.Warn("Database and RetentionPolicy options have no effect with UDP.")
config.Database = ""
config.RetentionPolicy = ""
}
case "http":
case protocolHTTP:
if u, err := url.Parse(config.Address); err == nil {
if u.Scheme != "http" && u.Scheme != "https" {
log.Warnf("InfluxDB address %s should specify a scheme of http or https, defaulting to http.", config.Address)
logger.Warnf("InfluxDB address %s should specify a scheme (http or https): falling back on HTTP.", config.Address)
config.Address = "http://" + config.Address
}
} else {
log.Errorf("Unable to parse influxdb address: %v, defaulting to udp.", err)
config.Protocol = "udp"
logger.Errorf("Unable to parse the InfluxDB address %v: falling back on UDP.", err)
config.Protocol = protocolUDP
config.Database = ""
config.RetentionPolicy = ""
}
default:
log.Warnf("Unsupported protocol: %s, defaulting to udp.", config.Protocol)
config.Protocol = "udp"
logger.Warnf("Unsupported protocol %s: falling back on UDP.", config.Protocol)
config.Protocol = protocolUDP
config.Database = ""
config.RetentionPolicy = ""
}
@ -101,16 +109,16 @@ func initInfluxDBClient(config *types.InfluxDB) *influx.Influx {
RetentionPolicy: config.RetentionPolicy,
},
kitlog.LoggerFunc(func(keyvals ...interface{}) error {
log.Info(keyvals)
log.WithoutContext().WithField(log.MetricsProviderName, "influxdb").Info(keyvals)
return nil
}))
}
// initInfluxDBTicker initializes metrics pusher
func initInfluxDBTicker(config *types.InfluxDB) *time.Ticker {
func initInfluxDBTicker(ctx context.Context, config *types.InfluxDB) *time.Ticker {
pushInterval, err := time.ParseDuration(config.PushInterval)
if err != nil {
log.Warnf("Unable to parse %s into pushInterval, using 10s as default value", config.PushInterval)
log.FromContext(ctx).Warnf("Unable to parse %s from config.PushInterval: using 10s as the default value", config.PushInterval)
pushInterval = 10 * time.Second
}
@ -144,8 +152,10 @@ func (w *influxDBWriter) Write(bp influxdb.BatchPoints) error {
defer c.Close()
if writeErr := c.Write(bp); writeErr != nil {
log.Errorf("Error writing to influx: %s", writeErr.Error())
if handleErr := w.handleWriteError(c, writeErr); handleErr != nil {
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "influxdb"))
log.FromContext(ctx).Errorf("Error while writing to InfluxDB: %s", writeErr.Error())
if handleErr := w.handleWriteError(ctx, c, writeErr); handleErr != nil {
return handleErr
}
// Retry write after successful handling of writeErr
@ -168,8 +178,8 @@ func (w *influxDBWriter) initWriteClient() (influxdb.Client, error) {
})
}
func (w *influxDBWriter) handleWriteError(c influxdb.Client, writeErr error) error {
if w.config.Protocol != "http" {
func (w *influxDBWriter) handleWriteError(ctx context.Context, c influxdb.Client, writeErr error) error {
if w.config.Protocol != protocolHTTP {
return writeErr
}
@ -184,7 +194,9 @@ func (w *influxDBWriter) handleWriteError(c influxdb.Client, writeErr error) err
qStr = fmt.Sprintf("%s WITH NAME \"%s\"", qStr, w.config.RetentionPolicy)
}
log.Debugf("Influx database does not exist, attempting to create with query: %s", qStr)
logger := log.FromContext(ctx)
logger.Debugf("InfluxDB database not found: attempting to create one with %s", qStr)
q := influxdb.NewQuery(qStr, "", "")
response, queryErr := c.Query(q)
@ -192,10 +204,10 @@ func (w *influxDBWriter) handleWriteError(c influxdb.Client, writeErr error) err
queryErr = response.Error()
}
if queryErr != nil {
log.Errorf("Error creating InfluxDB database: %s", queryErr)
logger.Errorf("Error while creating the InfluxDB database %s", queryErr)
return queryErr
}
log.Debugf("Successfully created influx database: %s", w.config.Database)
logger.Debugf("Successfully created the InfluxDB database %s", w.config.Database)
return nil
}

View file

@ -1,6 +1,7 @@
package metrics
import (
"context"
"fmt"
"io/ioutil"
"net/http"
@ -19,7 +20,7 @@ func TestInfluxDB(t *testing.T) {
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second
influxDBRegistry := RegisterInfluxDB(&types.InfluxDB{Address: ":8089", PushInterval: "1s"})
influxDBRegistry := RegisterInfluxDB(context.Background(), &types.InfluxDB{Address: ":8089", PushInterval: "1s"})
defer StopInfluxDB()
if !influxDBRegistry.IsEnabled() {
@ -79,7 +80,7 @@ func TestInfluxDBHTTP(t *testing.T) {
}))
defer ts.Close()
influxDBRegistry := RegisterInfluxDB(&types.InfluxDB{Address: ts.URL, Protocol: "http", PushInterval: "1s", Database: "test", RetentionPolicy: "autogen"})
influxDBRegistry := RegisterInfluxDB(context.Background(), &types.InfluxDB{Address: ts.URL, Protocol: "http", PushInterval: "1s", Database: "test", RetentionPolicy: "autogen"})
defer StopInfluxDB()
if !influxDBRegistry.IsEnabled() {

View file

@ -1,12 +1,14 @@
package metrics
import (
"context"
"net/http"
"sort"
"strings"
"sync"
"github.com/containous/mux"
"github.com/containous/traefik/config"
"github.com/containous/traefik/log"
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
@ -60,17 +62,17 @@ var promState = newPrometheusState()
// PrometheusHandler exposes Prometheus routes.
type PrometheusHandler struct{}
// AddRoutes adds Prometheus routes on a router.
func (h PrometheusHandler) AddRoutes(router *mux.Router) {
// Append adds Prometheus routes on a router.
func (h PrometheusHandler) Append(router *mux.Router) {
router.Methods(http.MethodGet).Path("/metrics").Handler(promhttp.Handler())
}
// RegisterPrometheus registers all Prometheus metrics.
// It must be called only once and failing to register the metrics will lead to a panic.
func RegisterPrometheus(config *types.Prometheus) Registry {
func RegisterPrometheus(ctx context.Context, config *types.Prometheus) Registry {
standardRegistry := initStandardRegistry(config)
if !registerPromState() {
if !registerPromState(ctx) {
return nil
}
@ -172,13 +174,14 @@ func initStandardRegistry(config *types.Prometheus) Registry {
}
}
func registerPromState() bool {
func registerPromState(ctx context.Context) bool {
if err := stdprometheus.Register(promState); err != nil {
logger := log.FromContext(ctx)
if _, ok := err.(stdprometheus.AlreadyRegisteredError); !ok {
log.Errorf("Unable to register Traefik to Prometheus: %v", err)
logger.Errorf("Unable to register Traefik to Prometheus: %v", err)
return false
}
log.Debug("Prometheus collector already registered.")
logger.Debug("Prometheus collector already registered.")
}
return true
}
@ -186,23 +189,24 @@ func registerPromState() bool {
// OnConfigurationUpdate receives the current configuration from Traefik.
// It then converts the configuration to the optimized package internal format
// and sets it to the promState.
func OnConfigurationUpdate(configurations types.Configurations) {
func OnConfigurationUpdate(configurations config.Configurations) {
dynamicConfig := newDynamicConfig()
for _, config := range configurations {
for _, frontend := range config.Frontends {
for _, entrypointName := range frontend.EntryPoints {
dynamicConfig.entrypoints[entrypointName] = true
}
}
for backendName, backend := range config.Backends {
dynamicConfig.backends[backendName] = make(map[string]bool)
for _, server := range backend.Servers {
dynamicConfig.backends[backendName][server.URL] = true
}
}
}
// FIXME metrics
// for _, config := range configurations {
// for _, frontend := range config.Frontends {
// for _, entrypointName := range frontend.EntryPoints {
// dynamicConfig.entrypoints[entrypointName] = true
// }
// }
//
// for backendName, backend := range config.Backends {
// dynamicConfig.backends[backendName] = make(map[string]bool)
// for _, server := range backend.Servers {
// dynamicConfig.backends[backendName][server.URL] = true
// }
// }
// }
promState.SetDynamicConfig(dynamicConfig)
}

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