2018-06-11 09:36:03 +00:00
package server
import (
2018-11-14 09:18:03 +00:00
"context"
2018-06-11 09:36:03 +00:00
"encoding/json"
"net/http"
"reflect"
"time"
2018-11-14 09:18:03 +00:00
"github.com/containous/alice"
2018-06-11 09:36:03 +00:00
"github.com/containous/mux"
2019-07-10 07:26:04 +00:00
"github.com/containous/traefik/pkg/config/dynamic"
2019-07-15 15:04:04 +00:00
"github.com/containous/traefik/pkg/config/runtime"
2019-03-15 08:42:03 +00:00
"github.com/containous/traefik/pkg/log"
2019-07-18 19:36:05 +00:00
"github.com/containous/traefik/pkg/metrics"
2019-03-15 08:42:03 +00:00
"github.com/containous/traefik/pkg/middlewares/accesslog"
2019-07-18 19:36:05 +00:00
metricsmiddleware "github.com/containous/traefik/pkg/middlewares/metrics"
2019-03-15 08:42:03 +00:00
"github.com/containous/traefik/pkg/middlewares/requestdecorator"
"github.com/containous/traefik/pkg/middlewares/tracing"
"github.com/containous/traefik/pkg/responsemodifiers"
"github.com/containous/traefik/pkg/server/middleware"
"github.com/containous/traefik/pkg/server/router"
routertcp "github.com/containous/traefik/pkg/server/router/tcp"
"github.com/containous/traefik/pkg/server/service"
"github.com/containous/traefik/pkg/server/service/tcp"
tcpCore "github.com/containous/traefik/pkg/tcp"
2018-06-11 09:36:03 +00:00
"github.com/eapache/channels"
2018-07-03 10:44:04 +00:00
"github.com/sirupsen/logrus"
2018-06-11 09:36:03 +00:00
)
2019-01-18 14:18:04 +00:00
// loadConfiguration manages dynamically routers, middlewares, servers and TLS configurations
2019-07-10 07:26:04 +00:00
func ( s * Server ) loadConfiguration ( configMsg dynamic . Message ) {
currentConfigurations := s . currentConfigurations . Get ( ) . ( dynamic . Configurations )
2018-06-11 09:36:03 +00:00
// Copy configurations to new map so we don't change current if LoadConfig fails
2019-07-09 13:18:04 +00:00
newConfigurations := currentConfigurations . DeepCopy ( )
2018-06-11 09:36:03 +00:00
newConfigurations [ configMsg . ProviderName ] = configMsg . Configuration
s . metricsRegistry . ConfigReloadsCounter ( ) . Add ( 1 )
2019-03-14 08:30:04 +00:00
handlersTCP := s . loadConfigurationTCP ( newConfigurations )
for entryPointName , router := range handlersTCP {
s . entryPointsTCP [ entryPointName ] . switchRouter ( router )
2018-11-14 09:18:03 +00:00
}
2018-06-11 09:36:03 +00:00
2019-03-14 08:30:04 +00:00
s . metricsRegistry . LastConfigReloadSuccessGauge ( ) . Set ( float64 ( time . Now ( ) . Unix ( ) ) )
2018-06-11 09:36:03 +00:00
s . currentConfigurations . Set ( newConfigurations )
for _ , listener := range s . configurationListeners {
listener ( * configMsg . Configuration )
}
2019-07-18 19:36:05 +00:00
if s . metricsRegistry . IsEpEnabled ( ) || s . metricsRegistry . IsSvcEnabled ( ) {
var entrypoints [ ] string
for key := range s . entryPointsTCP {
entrypoints = append ( entrypoints , key )
}
metrics . OnConfigurationUpdate ( newConfigurations , entrypoints )
}
2018-06-11 09:36:03 +00:00
}
2019-03-14 08:30:04 +00:00
// loadConfigurationTCP returns a new gorilla.mux Route from the specified global configuration and the dynamic
2018-06-11 09:36:03 +00:00
// provider configurations.
2019-07-10 07:26:04 +00:00
func ( s * Server ) loadConfigurationTCP ( configurations dynamic . Configurations ) map [ string ] * tcpCore . Router {
2018-11-14 09:18:03 +00:00
ctx := context . TODO ( )
2018-06-11 09:36:03 +00:00
2019-03-14 08:30:04 +00:00
var entryPoints [ ] string
for entryPointName := range s . entryPointsTCP {
entryPoints = append ( entryPoints , entryPointName )
}
2019-01-15 13:28:04 +00:00
conf := mergeConfiguration ( configurations )
2018-06-11 09:36:03 +00:00
2019-06-27 21:58:03 +00:00
s . tlsManager . UpdateConfigs ( conf . TLS . Stores , conf . TLS . Options , conf . TLS . Certificates )
2019-03-14 08:30:04 +00:00
2019-07-15 15:04:04 +00:00
rtConf := runtime . NewConfig ( conf )
2019-05-16 08:58:06 +00:00
handlersNonTLS , handlersTLS := s . createHTTPHandlers ( ctx , rtConf , entryPoints )
2019-06-17 16:14:08 +00:00
routersTCP := s . createTCPRouters ( ctx , rtConf , entryPoints , handlersNonTLS , handlersTLS )
2019-05-16 08:58:06 +00:00
rtConf . PopulateUsedBy ( )
2019-03-14 08:30:04 +00:00
return routersTCP
2018-06-11 09:36:03 +00:00
}
2019-05-16 08:58:06 +00:00
// the given configuration must not be nil. its fields will get mutated.
2019-07-15 15:04:04 +00:00
func ( s * Server ) createTCPRouters ( ctx context . Context , configuration * runtime . Configuration , entryPoints [ ] string , handlers map [ string ] http . Handler , handlersTLS map [ string ] http . Handler ) map [ string ] * tcpCore . Router {
2019-03-14 08:30:04 +00:00
if configuration == nil {
return make ( map [ string ] * tcpCore . Router )
2018-06-11 09:36:03 +00:00
}
2019-05-16 08:58:06 +00:00
serviceManager := tcp . NewManager ( configuration )
2019-06-17 16:14:08 +00:00
routerManager := routertcp . NewManager ( configuration , serviceManager , handlers , handlersTLS , s . tlsManager )
2019-03-14 08:30:04 +00:00
return routerManager . BuildHandlers ( ctx , entryPoints )
}
2019-05-16 08:58:06 +00:00
// createHTTPHandlers returns, for the given configuration and entryPoints, the HTTP handlers for non-TLS connections, and for the TLS ones. the given configuration must not be nil. its fields will get mutated.
2019-07-15 15:04:04 +00:00
func ( s * Server ) createHTTPHandlers ( ctx context . Context , configuration * runtime . Configuration , entryPoints [ ] string ) ( map [ string ] http . Handler , map [ string ] http . Handler ) {
2019-07-18 19:36:05 +00:00
serviceManager := service . NewManager ( configuration . Services , s . defaultRoundTripper , s . metricsRegistry )
2018-11-14 09:18:03 +00:00
middlewaresBuilder := middleware . NewBuilder ( configuration . Middlewares , serviceManager )
responseModifierFactory := responsemodifiers . NewBuilder ( configuration . Middlewares )
2019-06-17 16:14:08 +00:00
routerManager := router . NewManager ( configuration , serviceManager , middlewaresBuilder , responseModifierFactory )
2018-06-11 09:36:03 +00:00
2019-03-14 08:30:04 +00:00
handlersNonTLS := routerManager . BuildHandlers ( ctx , entryPoints , false )
handlersTLS := routerManager . BuildHandlers ( ctx , entryPoints , true )
2018-06-11 09:36:03 +00:00
2018-11-14 09:18:03 +00:00
routerHandlers := make ( map [ string ] http . Handler )
for _ , entryPointName := range entryPoints {
2019-05-16 08:58:06 +00:00
internalMuxRouter := mux . NewRouter ( ) . SkipClean ( true )
2018-09-17 18:40:04 +00:00
2018-11-14 09:18:03 +00:00
ctx = log . With ( ctx , log . Str ( log . EntryPointName , entryPointName ) )
2018-06-11 09:36:03 +00:00
2019-03-14 08:30:04 +00:00
factory := s . entryPointsTCP [ entryPointName ] . RouteAppenderFactory
2018-11-14 09:18:03 +00:00
if factory != nil {
// FIXME remove currentConfigurations
2019-05-16 08:58:06 +00:00
appender := factory . NewAppender ( ctx , middlewaresBuilder , configuration )
2018-11-14 09:18:03 +00:00
appender . Append ( internalMuxRouter )
}
2018-06-11 09:36:03 +00:00
2019-03-14 08:30:04 +00:00
if h , ok := handlersNonTLS [ entryPointName ] ; ok {
2018-11-14 09:18:03 +00:00
internalMuxRouter . NotFoundHandler = h
2018-06-11 09:36:03 +00:00
} else {
2018-11-27 16:42:04 +00:00
internalMuxRouter . NotFoundHandler = buildDefaultHTTPRouter ( )
2018-06-11 09:36:03 +00:00
}
2018-11-14 09:18:03 +00:00
routerHandlers [ entryPointName ] = internalMuxRouter
2018-06-11 09:36:03 +00:00
2018-11-14 09:18:03 +00:00
chain := alice . New ( )
2018-06-11 09:36:03 +00:00
2018-11-14 09:18:03 +00:00
if s . accessLoggerMiddleware != nil {
chain = chain . Append ( accesslog . WrapHandler ( s . accessLoggerMiddleware ) )
2018-06-11 09:36:03 +00:00
}
2018-11-14 09:18:03 +00:00
if s . tracer != nil {
chain = chain . Append ( tracing . WrapEntryPointHandler ( ctx , s . tracer , entryPointName ) )
2018-10-29 17:42:03 +00:00
}
2018-06-11 09:36:03 +00:00
2019-07-18 19:36:05 +00:00
if s . metricsRegistry . IsEpEnabled ( ) {
chain = chain . Append ( metricsmiddleware . WrapEntryPointHandler ( ctx , s . metricsRegistry , entryPointName ) )
}
2018-11-14 09:18:03 +00:00
chain = chain . Append ( requestdecorator . WrapHandler ( s . requestDecorator ) )
2018-06-11 09:36:03 +00:00
2018-11-14 09:18:03 +00:00
handler , err := chain . Then ( internalMuxRouter . NotFoundHandler )
2018-06-11 09:36:03 +00:00
if err != nil {
2018-11-14 09:18:03 +00:00
log . FromContext ( ctx ) . Error ( err )
continue
2018-06-11 09:36:03 +00:00
}
2018-11-14 09:18:03 +00:00
internalMuxRouter . NotFoundHandler = handler
2019-03-14 08:30:04 +00:00
handlerTLS , ok := handlersTLS [ entryPointName ]
if ok {
handlerTLSWithMiddlewares , err := chain . Then ( handlerTLS )
if err != nil {
log . FromContext ( ctx ) . Error ( err )
continue
}
handlersTLS [ entryPointName ] = handlerTLSWithMiddlewares
}
}
return routerHandlers , handlersTLS
}
2019-07-10 07:26:04 +00:00
func isEmptyConfiguration ( conf * dynamic . Configuration ) bool {
2019-03-14 08:30:04 +00:00
if conf == nil {
return true
}
if conf . TCP == nil {
2019-07-10 07:26:04 +00:00
conf . TCP = & dynamic . TCPConfiguration { }
2019-03-14 08:30:04 +00:00
}
if conf . HTTP == nil {
2019-07-10 07:26:04 +00:00
conf . HTTP = & dynamic . HTTPConfiguration { }
2018-06-11 09:36:03 +00:00
}
2019-03-14 08:30:04 +00:00
return conf . HTTP . Routers == nil &&
conf . HTTP . Services == nil &&
conf . HTTP . Middlewares == nil &&
2019-06-27 21:58:03 +00:00
( conf . TLS == nil || conf . TLS . Certificates == nil && conf . TLS . Stores == nil && conf . TLS . Options == nil ) &&
2019-03-14 08:30:04 +00:00
conf . TCP . Routers == nil &&
conf . TCP . Services == nil
2018-06-11 09:36:03 +00:00
}
2019-07-10 07:26:04 +00:00
func ( s * Server ) preLoadConfiguration ( configMsg dynamic . Message ) {
2019-03-14 08:30:04 +00:00
s . defaultConfigurationValues ( configMsg . Configuration . HTTP )
2019-07-10 07:26:04 +00:00
currentConfigurations := s . currentConfigurations . Get ( ) . ( dynamic . Configurations )
2018-06-11 09:36:03 +00:00
2018-11-14 09:18:03 +00:00
logger := log . WithoutContext ( ) . WithField ( log . ProviderName , configMsg . ProviderName )
2018-07-03 10:44:04 +00:00
if log . GetLevel ( ) == logrus . DebugLevel {
2019-07-12 23:24:03 +00:00
copyConf := configMsg . Configuration . DeepCopy ( )
if copyConf . TLS != nil {
copyConf . TLS . Certificates = nil
for _ , v := range copyConf . TLS . Stores {
v . DefaultCertificate = nil
}
}
jsonConf , err := json . Marshal ( copyConf )
if err != nil {
logger . Errorf ( "Could not marshal dynamic configuration: %v" , err )
logger . Debugf ( "Configuration received from provider %s: [struct] %#v" , configMsg . ProviderName , copyConf )
} else {
logger . Debugf ( "Configuration received from provider %s: %s" , configMsg . ProviderName , string ( jsonConf ) )
}
2018-07-03 10:44:04 +00:00
}
2018-06-11 09:36:03 +00:00
2019-03-14 08:30:04 +00:00
if isEmptyConfiguration ( configMsg . Configuration ) {
2018-11-14 09:18:03 +00:00
logger . Infof ( "Skipping empty Configuration for provider %s" , configMsg . ProviderName )
2018-06-11 09:36:03 +00:00
return
}
if reflect . DeepEqual ( currentConfigurations [ configMsg . ProviderName ] , configMsg . Configuration ) {
2018-11-14 09:18:03 +00:00
logger . Infof ( "Skipping same configuration for provider %s" , configMsg . ProviderName )
2018-06-11 09:36:03 +00:00
return
}
providerConfigUpdateCh , ok := s . providerConfigUpdateMap [ configMsg . ProviderName ]
if ! ok {
2019-07-10 07:26:04 +00:00
providerConfigUpdateCh = make ( chan dynamic . Message )
2018-06-11 09:36:03 +00:00
s . providerConfigUpdateMap [ configMsg . ProviderName ] = providerConfigUpdateCh
s . routinesPool . Go ( func ( stop chan bool ) {
2018-11-27 16:42:04 +00:00
s . throttleProviderConfigReload ( s . providersThrottleDuration , s . configurationValidatedChan , providerConfigUpdateCh , stop )
2018-06-11 09:36:03 +00:00
} )
}
providerConfigUpdateCh <- configMsg
}
2019-07-10 07:26:04 +00:00
func ( s * Server ) defaultConfigurationValues ( configuration * dynamic . HTTPConfiguration ) {
2018-11-14 09:18:03 +00:00
// FIXME create a config hook
2018-06-11 09:36:03 +00:00
}
func ( s * Server ) listenConfigurations ( stop chan bool ) {
for {
select {
case <- stop :
return
case configMsg , ok := <- s . configurationValidatedChan :
if ! ok || configMsg . Configuration == nil {
return
}
s . loadConfiguration ( configMsg )
}
}
}
// throttleProviderConfigReload throttles the configuration reload speed for a single provider.
// It will immediately publish a new configuration and then only publish the next configuration after the throttle duration.
// Note that in the case it receives N new configs in the timeframe of the throttle duration after publishing,
// it will publish the last of the newly received configurations.
2019-07-10 07:26:04 +00:00
func ( s * Server ) throttleProviderConfigReload ( throttle time . Duration , publish chan <- dynamic . Message , in <- chan dynamic . Message , stop chan bool ) {
2018-06-11 09:36:03 +00:00
ring := channels . NewRingChannel ( 1 )
defer ring . Close ( )
s . routinesPool . Go ( func ( stop chan bool ) {
for {
select {
case <- stop :
return
case nextConfig := <- ring . Out ( ) :
2019-07-10 07:26:04 +00:00
if config , ok := nextConfig . ( dynamic . Message ) ; ok {
2018-09-06 12:24:03 +00:00
publish <- config
time . Sleep ( throttle )
}
2018-06-11 09:36:03 +00:00
}
}
} )
for {
select {
case <- stop :
return
case nextConfig := <- in :
ring . In ( ) <- nextConfig
}
}
}
2018-11-27 16:42:04 +00:00
func buildDefaultHTTPRouter ( ) * mux . Router {
2018-11-14 09:18:03 +00:00
rt := mux . NewRouter ( )
rt . NotFoundHandler = http . HandlerFunc ( http . NotFound )
rt . SkipClean ( true )
return rt
}