2019-01-18 15:18:04 +01:00
package provider
import (
2019-01-21 19:06:02 +01:00
"bytes"
2019-01-18 15:18:04 +01:00
"context"
"reflect"
"sort"
2019-01-21 19:06:02 +01:00
"strings"
"text/template"
"unicode"
2019-01-18 15:18:04 +01:00
2021-01-20 15:10:04 +01:00
"github.com/Masterminds/sprig/v3"
2020-09-16 15:46:04 +02:00
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
2019-01-18 15:18:04 +01:00
)
// Merge Merges multiple configurations.
2019-07-10 09:26:04 +02:00
func Merge ( ctx context . Context , configurations map [ string ] * dynamic . Configuration ) * dynamic . Configuration {
2019-01-18 15:18:04 +01:00
logger := log . FromContext ( ctx )
2019-07-10 09:26:04 +02:00
configuration := & dynamic . Configuration {
HTTP : & dynamic . HTTPConfiguration {
2021-07-15 17:32:11 +05:30
Routers : make ( map [ string ] * dynamic . Router ) ,
Middlewares : make ( map [ string ] * dynamic . Middleware ) ,
Services : make ( map [ string ] * dynamic . Service ) ,
ServersTransports : make ( map [ string ] * dynamic . ServersTransport ) ,
2019-03-14 09:30:04 +01:00
} ,
2019-07-10 09:26:04 +02:00
TCP : & dynamic . TCPConfiguration {
2021-06-11 15:30:05 +02:00
Routers : make ( map [ string ] * dynamic . TCPRouter ) ,
Services : make ( map [ string ] * dynamic . TCPService ) ,
Middlewares : make ( map [ string ] * dynamic . TCPMiddleware ) ,
2019-03-14 09:30:04 +01:00
} ,
2020-02-11 01:26:04 +01:00
UDP : & dynamic . UDPConfiguration {
Routers : make ( map [ string ] * dynamic . UDPRouter ) ,
Services : make ( map [ string ] * dynamic . UDPService ) ,
} ,
2019-01-18 15:18:04 +01:00
}
servicesToDelete := map [ string ] struct { } { }
services := map [ string ] [ ] string { }
routersToDelete := map [ string ] struct { } { }
routers := map [ string ] [ ] string { }
2019-03-21 15:22:06 +01:00
servicesTCPToDelete := map [ string ] struct { } { }
servicesTCP := map [ string ] [ ] string { }
routersTCPToDelete := map [ string ] struct { } { }
routersTCP := map [ string ] [ ] string { }
2020-02-20 22:24:05 +01:00
servicesUDPToDelete := map [ string ] struct { } { }
servicesUDP := map [ string ] [ ] string { }
routersUDPToDelete := map [ string ] struct { } { }
routersUDP := map [ string ] [ ] string { }
2019-01-18 15:18:04 +01:00
middlewaresToDelete := map [ string ] struct { } { }
middlewares := map [ string ] [ ] string { }
2021-06-11 15:30:05 +02:00
middlewaresTCPToDelete := map [ string ] struct { } { }
middlewaresTCP := map [ string ] [ ] string { }
2021-07-15 17:32:11 +05:30
transportsToDelete := map [ string ] struct { } { }
transports := map [ string ] [ ] string { }
2019-01-18 15:18:04 +01:00
var sortedKeys [ ] string
for key := range configurations {
sortedKeys = append ( sortedKeys , key )
}
sort . Strings ( sortedKeys )
for _ , root := range sortedKeys {
conf := configurations [ root ]
2019-03-14 09:30:04 +01:00
for serviceName , service := range conf . HTTP . Services {
2019-01-18 15:18:04 +01:00
services [ serviceName ] = append ( services [ serviceName ] , root )
2019-03-14 09:30:04 +01:00
if ! AddService ( configuration . HTTP , serviceName , service ) {
2019-01-18 15:18:04 +01:00
servicesToDelete [ serviceName ] = struct { } { }
}
}
2019-03-14 09:30:04 +01:00
for routerName , router := range conf . HTTP . Routers {
2019-01-18 15:18:04 +01:00
routers [ routerName ] = append ( routers [ routerName ] , root )
2019-03-14 09:30:04 +01:00
if ! AddRouter ( configuration . HTTP , routerName , router ) {
2019-01-18 15:18:04 +01:00
routersToDelete [ routerName ] = struct { } { }
}
}
2021-07-15 17:32:11 +05:30
for transportName , transport := range conf . HTTP . ServersTransports {
transports [ transportName ] = append ( transports [ transportName ] , root )
if ! AddTransport ( configuration . HTTP , transportName , transport ) {
transportsToDelete [ transportName ] = struct { } { }
}
}
2019-03-21 15:22:06 +01:00
for serviceName , service := range conf . TCP . Services {
servicesTCP [ serviceName ] = append ( servicesTCP [ serviceName ] , root )
if ! AddServiceTCP ( configuration . TCP , serviceName , service ) {
servicesTCPToDelete [ serviceName ] = struct { } { }
}
}
for routerName , router := range conf . TCP . Routers {
routersTCP [ routerName ] = append ( routersTCP [ routerName ] , root )
if ! AddRouterTCP ( configuration . TCP , routerName , router ) {
routersTCPToDelete [ routerName ] = struct { } { }
}
}
2020-02-20 22:24:05 +01:00
for serviceName , service := range conf . UDP . Services {
servicesUDP [ serviceName ] = append ( servicesUDP [ serviceName ] , root )
if ! AddServiceUDP ( configuration . UDP , serviceName , service ) {
servicesUDPToDelete [ serviceName ] = struct { } { }
}
}
for routerName , router := range conf . UDP . Routers {
routersUDP [ routerName ] = append ( routersUDP [ routerName ] , root )
if ! AddRouterUDP ( configuration . UDP , routerName , router ) {
routersUDPToDelete [ routerName ] = struct { } { }
}
}
2019-03-14 09:30:04 +01:00
for middlewareName , middleware := range conf . HTTP . Middlewares {
2019-01-18 15:18:04 +01:00
middlewares [ middlewareName ] = append ( middlewares [ middlewareName ] , root )
2019-03-14 09:30:04 +01:00
if ! AddMiddleware ( configuration . HTTP , middlewareName , middleware ) {
2019-01-18 15:18:04 +01:00
middlewaresToDelete [ middlewareName ] = struct { } { }
}
}
2021-06-11 15:30:05 +02:00
for middlewareName , middleware := range conf . TCP . Middlewares {
middlewaresTCP [ middlewareName ] = append ( middlewaresTCP [ middlewareName ] , root )
if ! AddMiddlewareTCP ( configuration . TCP , middlewareName , middleware ) {
middlewaresTCPToDelete [ middlewareName ] = struct { } { }
}
}
2019-01-18 15:18:04 +01:00
}
for serviceName := range servicesToDelete {
logger . WithField ( log . ServiceName , serviceName ) .
Errorf ( "Service defined multiple times with different configurations in %v" , services [ serviceName ] )
2019-03-14 09:30:04 +01:00
delete ( configuration . HTTP . Services , serviceName )
2019-01-18 15:18:04 +01:00
}
for routerName := range routersToDelete {
logger . WithField ( log . RouterName , routerName ) .
Errorf ( "Router defined multiple times with different configurations in %v" , routers [ routerName ] )
2019-03-14 09:30:04 +01:00
delete ( configuration . HTTP . Routers , routerName )
2019-01-18 15:18:04 +01:00
}
2021-07-15 17:32:11 +05:30
for transportName := range transportsToDelete {
logger . WithField ( log . ServersTransportName , transportName ) .
Errorf ( "ServersTransport defined multiple times with different configurations in %v" , transports [ transportName ] )
delete ( configuration . HTTP . ServersTransports , transportName )
}
2019-03-21 15:22:06 +01:00
for serviceName := range servicesTCPToDelete {
logger . WithField ( log . ServiceName , serviceName ) .
Errorf ( "Service TCP defined multiple times with different configurations in %v" , servicesTCP [ serviceName ] )
delete ( configuration . TCP . Services , serviceName )
}
for routerName := range routersTCPToDelete {
logger . WithField ( log . RouterName , routerName ) .
Errorf ( "Router TCP defined multiple times with different configurations in %v" , routersTCP [ routerName ] )
delete ( configuration . TCP . Routers , routerName )
}
2020-02-20 22:24:05 +01:00
for serviceName := range servicesUDPToDelete {
logger . WithField ( log . ServiceName , serviceName ) .
Errorf ( "UDP service defined multiple times with different configurations in %v" , servicesUDP [ serviceName ] )
delete ( configuration . UDP . Services , serviceName )
}
for routerName := range routersUDPToDelete {
logger . WithField ( log . RouterName , routerName ) .
Errorf ( "UDP router defined multiple times with different configurations in %v" , routersUDP [ routerName ] )
delete ( configuration . UDP . Routers , routerName )
}
2019-01-18 15:18:04 +01:00
for middlewareName := range middlewaresToDelete {
logger . WithField ( log . MiddlewareName , middlewareName ) .
Errorf ( "Middleware defined multiple times with different configurations in %v" , middlewares [ middlewareName ] )
2019-03-14 09:30:04 +01:00
delete ( configuration . HTTP . Middlewares , middlewareName )
2019-01-18 15:18:04 +01:00
}
2021-06-11 15:30:05 +02:00
for middlewareName := range middlewaresTCPToDelete {
logger . WithField ( log . MiddlewareName , middlewareName ) .
Errorf ( "TCP Middleware defined multiple times with different configurations in %v" , middlewaresTCP [ middlewareName ] )
delete ( configuration . TCP . Middlewares , middlewareName )
}
2019-01-18 15:18:04 +01:00
return configuration
}
2019-03-21 15:22:06 +01:00
// AddServiceTCP Adds a service to a configurations.
2019-07-10 09:26:04 +02:00
func AddServiceTCP ( configuration * dynamic . TCPConfiguration , serviceName string , service * dynamic . TCPService ) bool {
2019-03-21 15:22:06 +01:00
if _ , ok := configuration . Services [ serviceName ] ; ! ok {
configuration . Services [ serviceName ] = service
return true
}
if ! configuration . Services [ serviceName ] . LoadBalancer . Mergeable ( service . LoadBalancer ) {
return false
}
2020-12-15 16:40:05 +01:00
uniq := map [ string ] struct { } { }
for _ , server := range configuration . Services [ serviceName ] . LoadBalancer . Servers {
uniq [ server . Address ] = struct { } { }
}
for _ , server := range service . LoadBalancer . Servers {
if _ , ok := uniq [ server . Address ] ; ! ok {
configuration . Services [ serviceName ] . LoadBalancer . Servers = append ( configuration . Services [ serviceName ] . LoadBalancer . Servers , server )
}
}
2019-03-21 15:22:06 +01:00
return true
}
2020-12-15 16:40:05 +01:00
// AddRouterTCP Adds a router to a configurations.
func AddRouterTCP ( configuration * dynamic . TCPConfiguration , routerName string , router * dynamic . TCPRouter ) bool {
if _ , ok := configuration . Routers [ routerName ] ; ! ok {
configuration . Routers [ routerName ] = router
return true
}
return reflect . DeepEqual ( configuration . Routers [ routerName ] , router )
}
2021-06-11 15:30:05 +02:00
// AddMiddlewareTCP Adds a middleware to a configurations.
func AddMiddlewareTCP ( configuration * dynamic . TCPConfiguration , middlewareName string , middleware * dynamic . TCPMiddleware ) bool {
if _ , ok := configuration . Middlewares [ middlewareName ] ; ! ok {
configuration . Middlewares [ middlewareName ] = middleware
return true
}
return reflect . DeepEqual ( configuration . Middlewares [ middlewareName ] , middleware )
}
2020-02-20 22:24:05 +01:00
// AddServiceUDP adds a service to a configuration.
func AddServiceUDP ( configuration * dynamic . UDPConfiguration , serviceName string , service * dynamic . UDPService ) bool {
if _ , ok := configuration . Services [ serviceName ] ; ! ok {
configuration . Services [ serviceName ] = service
return true
}
if ! configuration . Services [ serviceName ] . LoadBalancer . Mergeable ( service . LoadBalancer ) {
return false
}
2020-12-15 16:40:05 +01:00
uniq := map [ string ] struct { } { }
for _ , server := range configuration . Services [ serviceName ] . LoadBalancer . Servers {
uniq [ server . Address ] = struct { } { }
}
2020-02-20 22:24:05 +01:00
2020-12-15 16:40:05 +01:00
for _ , server := range service . LoadBalancer . Servers {
if _ , ok := uniq [ server . Address ] ; ! ok {
configuration . Services [ serviceName ] . LoadBalancer . Servers = append ( configuration . Services [ serviceName ] . LoadBalancer . Servers , server )
}
2019-03-21 15:22:06 +01:00
}
2020-12-15 16:40:05 +01:00
return true
2019-03-21 15:22:06 +01:00
}
2020-02-20 22:24:05 +01:00
// AddRouterUDP adds a router to a configuration.
func AddRouterUDP ( configuration * dynamic . UDPConfiguration , routerName string , router * dynamic . UDPRouter ) bool {
if _ , ok := configuration . Routers [ routerName ] ; ! ok {
configuration . Routers [ routerName ] = router
return true
}
return reflect . DeepEqual ( configuration . Routers [ routerName ] , router )
}
2019-01-18 15:18:04 +01:00
// AddService Adds a service to a configurations.
2019-07-10 09:26:04 +02:00
func AddService ( configuration * dynamic . HTTPConfiguration , serviceName string , service * dynamic . Service ) bool {
2019-01-18 15:18:04 +01:00
if _ , ok := configuration . Services [ serviceName ] ; ! ok {
configuration . Services [ serviceName ] = service
return true
}
if ! configuration . Services [ serviceName ] . LoadBalancer . Mergeable ( service . LoadBalancer ) {
return false
}
2020-12-15 16:40:05 +01:00
uniq := map [ string ] struct { } { }
for _ , server := range configuration . Services [ serviceName ] . LoadBalancer . Servers {
uniq [ server . URL ] = struct { } { }
}
for _ , server := range service . LoadBalancer . Servers {
if _ , ok := uniq [ server . URL ] ; ! ok {
configuration . Services [ serviceName ] . LoadBalancer . Servers = append ( configuration . Services [ serviceName ] . LoadBalancer . Servers , server )
}
}
2019-01-18 15:18:04 +01:00
return true
}
// AddRouter Adds a router to a configurations.
2019-07-10 09:26:04 +02:00
func AddRouter ( configuration * dynamic . HTTPConfiguration , routerName string , router * dynamic . Router ) bool {
2019-01-18 15:18:04 +01:00
if _ , ok := configuration . Routers [ routerName ] ; ! ok {
configuration . Routers [ routerName ] = router
return true
}
return reflect . DeepEqual ( configuration . Routers [ routerName ] , router )
}
2021-07-15 17:32:11 +05:30
// AddTransport Adds a transport to a configurations.
func AddTransport ( configuration * dynamic . HTTPConfiguration , transportName string , transport * dynamic . ServersTransport ) bool {
if _ , ok := configuration . ServersTransports [ transportName ] ; ! ok {
configuration . ServersTransports [ transportName ] = transport
return true
}
return reflect . DeepEqual ( configuration . ServersTransports [ transportName ] , transport )
}
2019-01-18 15:18:04 +01:00
// AddMiddleware Adds a middleware to a configurations.
2019-07-10 09:26:04 +02:00
func AddMiddleware ( configuration * dynamic . HTTPConfiguration , middlewareName string , middleware * dynamic . Middleware ) bool {
2019-01-18 15:18:04 +01:00
if _ , ok := configuration . Middlewares [ middlewareName ] ; ! ok {
configuration . Middlewares [ middlewareName ] = middleware
return true
}
return reflect . DeepEqual ( configuration . Middlewares [ middlewareName ] , middleware )
}
2019-01-21 19:06:02 +01:00
// MakeDefaultRuleTemplate Creates the default rule template.
func MakeDefaultRuleTemplate ( defaultRule string , funcMap template . FuncMap ) ( * template . Template , error ) {
defaultFuncMap := sprig . TxtFuncMap ( )
defaultFuncMap [ "normalize" ] = Normalize
for k , fn := range funcMap {
defaultFuncMap [ k ] = fn
}
return template . New ( "defaultRule" ) . Funcs ( defaultFuncMap ) . Parse ( defaultRule )
}
2019-03-21 15:22:06 +01:00
// BuildTCPRouterConfiguration Builds a router configuration.
2019-07-10 09:26:04 +02:00
func BuildTCPRouterConfiguration ( ctx context . Context , configuration * dynamic . TCPConfiguration ) {
2019-03-21 15:22:06 +01:00
for routerName , router := range configuration . Routers {
loggerRouter := log . FromContext ( ctx ) . WithField ( log . RouterName , routerName )
if len ( router . Rule ) == 0 {
delete ( configuration . Routers , routerName )
loggerRouter . Errorf ( "Empty rule" )
continue
}
if len ( router . Service ) == 0 {
if len ( configuration . Services ) > 1 {
delete ( configuration . Routers , routerName )
loggerRouter .
Error ( "Could not define the service name for the router: too many services" )
continue
}
for serviceName := range configuration . Services {
router . Service = serviceName
}
}
}
}
2020-02-20 22:24:05 +01:00
// BuildUDPRouterConfiguration Builds a router configuration.
func BuildUDPRouterConfiguration ( ctx context . Context , configuration * dynamic . UDPConfiguration ) {
for routerName , router := range configuration . Routers {
loggerRouter := log . FromContext ( ctx ) . WithField ( log . RouterName , routerName )
if len ( router . Service ) > 0 {
continue
}
if len ( configuration . Services ) > 1 {
delete ( configuration . Routers , routerName )
loggerRouter .
Error ( "Could not define the service name for the router: too many services" )
continue
}
for serviceName := range configuration . Services {
router . Service = serviceName
break
}
}
}
2019-01-21 19:06:02 +01:00
// BuildRouterConfiguration Builds a router configuration.
2019-07-10 09:26:04 +02:00
func BuildRouterConfiguration ( ctx context . Context , configuration * dynamic . HTTPConfiguration , defaultRouterName string , defaultRuleTpl * template . Template , model interface { } ) {
2019-01-21 19:06:02 +01:00
if len ( configuration . Routers ) == 0 {
if len ( configuration . Services ) > 1 {
log . FromContext ( ctx ) . Info ( "Could not create a router for the container: too many services" )
} else {
2019-07-10 09:26:04 +02:00
configuration . Routers = make ( map [ string ] * dynamic . Router )
configuration . Routers [ defaultRouterName ] = & dynamic . Router { }
2019-01-21 19:06:02 +01:00
}
}
for routerName , router := range configuration . Routers {
2019-03-21 15:22:06 +01:00
loggerRouter := log . FromContext ( ctx ) . WithField ( log . RouterName , routerName )
2019-01-21 19:06:02 +01:00
if len ( router . Rule ) == 0 {
writer := & bytes . Buffer { }
if err := defaultRuleTpl . Execute ( writer , model ) ; err != nil {
loggerRouter . Errorf ( "Error while parsing default rule: %v" , err )
delete ( configuration . Routers , routerName )
continue
}
router . Rule = writer . String ( )
if len ( router . Rule ) == 0 {
loggerRouter . Error ( "Undefined rule" )
delete ( configuration . Routers , routerName )
continue
}
}
if len ( router . Service ) == 0 {
if len ( configuration . Services ) > 1 {
delete ( configuration . Routers , routerName )
loggerRouter .
Error ( "Could not define the service name for the router: too many services" )
continue
}
for serviceName := range configuration . Services {
router . Service = serviceName
}
}
}
}
// Normalize Replace all special chars with `-`.
func Normalize ( name string ) string {
fargs := func ( c rune ) bool {
return ! unicode . IsLetter ( c ) && ! unicode . IsNumber ( c )
}
// get function
return strings . Join ( strings . FieldsFunc ( name , fargs ) , "-" )
}