2019-10-15 18:34:08 +03:00
package consulcatalog
import (
"context"
"errors"
"fmt"
"net"
"github.com/hashicorp/consul/api"
2020-09-16 15:46:04 +02:00
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/config/label"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/provider"
"github.com/traefik/traefik/v2/pkg/provider/constraints"
2019-10-15 18:34:08 +03:00
)
2021-07-15 17:32:11 +05:30
func ( p * Provider ) buildConfiguration ( ctx context . Context , items [ ] itemData , certInfo * connectCert ) * dynamic . Configuration {
2019-10-15 18:34:08 +03:00
configurations := make ( map [ string ] * dynamic . Configuration )
for _ , item := range items {
2020-03-30 19:12:05 +02:00
svcName := provider . Normalize ( item . Node + "-" + item . Name + "-" + item . ID )
ctxSvc := log . With ( ctx , log . Str ( log . ServiceName , svcName ) )
2019-10-15 18:34:08 +03:00
if ! p . keepContainer ( ctxSvc , item ) {
continue
}
logger := log . FromContext ( ctxSvc )
confFromLabel , err := label . DecodeConfiguration ( item . Labels )
if err != nil {
logger . Error ( err )
continue
}
2020-02-20 22:24:05 +01:00
var tcpOrUDP bool
2019-10-15 18:34:08 +03:00
if len ( confFromLabel . TCP . Routers ) > 0 || len ( confFromLabel . TCP . Services ) > 0 {
2020-02-20 22:24:05 +01:00
tcpOrUDP = true
2019-10-15 18:34:08 +03:00
err := p . buildTCPServiceConfiguration ( ctxSvc , item , confFromLabel . TCP )
if err != nil {
logger . Error ( err )
continue
}
2021-07-15 17:32:11 +05:30
2019-10-15 18:34:08 +03:00
provider . BuildTCPRouterConfiguration ( ctxSvc , confFromLabel . TCP )
2020-02-20 22:24:05 +01:00
}
2019-10-15 18:34:08 +03:00
2020-02-20 22:24:05 +01:00
if len ( confFromLabel . UDP . Routers ) > 0 || len ( confFromLabel . UDP . Services ) > 0 {
tcpOrUDP = true
err := p . buildUDPServiceConfiguration ( ctxSvc , item , confFromLabel . UDP )
if err != nil {
logger . Error ( err )
2019-10-15 18:34:08 +03:00
continue
}
2020-02-20 22:24:05 +01:00
provider . BuildUDPRouterConfiguration ( ctxSvc , confFromLabel . UDP )
}
if tcpOrUDP && len ( confFromLabel . HTTP . Routers ) == 0 &&
len ( confFromLabel . HTTP . Middlewares ) == 0 &&
len ( confFromLabel . HTTP . Services ) == 0 {
configurations [ svcName ] = confFromLabel
continue
2019-10-15 18:34:08 +03:00
}
2021-07-15 17:32:11 +05:30
if item . ExtraConf . ConsulCatalog . Connect {
if confFromLabel . HTTP . ServersTransports == nil {
confFromLabel . HTTP . ServersTransports = make ( map [ string ] * dynamic . ServersTransport )
}
serversTransportKey := itemServersTransportKey ( item )
if confFromLabel . HTTP . ServersTransports [ serversTransportKey ] == nil {
confFromLabel . HTTP . ServersTransports [ serversTransportKey ] = certInfo . serversTransport ( item )
}
}
2019-10-15 18:34:08 +03:00
err = p . buildServiceConfiguration ( ctxSvc , item , confFromLabel . HTTP )
if err != nil {
logger . Error ( err )
continue
}
model := struct {
Name string
Labels map [ string ] string
} {
Name : item . Name ,
Labels : item . Labels ,
}
2020-03-30 19:12:05 +02:00
provider . BuildRouterConfiguration ( ctx , confFromLabel . HTTP , provider . Normalize ( item . Name ) , p . defaultRuleTpl , model )
2019-10-15 18:34:08 +03:00
configurations [ svcName ] = confFromLabel
}
return provider . Merge ( ctx , configurations )
}
func ( p * Provider ) keepContainer ( ctx context . Context , item itemData ) bool {
logger := log . FromContext ( ctx )
if ! item . ExtraConf . Enable {
logger . Debug ( "Filtering disabled item" )
return false
}
2021-07-15 17:32:11 +05:30
if ! p . ConnectAware && item . ExtraConf . ConsulCatalog . Connect {
logger . Debugf ( "Filtering out Connect aware item, Connect support is not enabled" )
return false
}
2019-11-29 17:16:05 +01:00
matches , err := constraints . MatchTags ( item . Tags , p . Constraints )
2019-10-15 18:34:08 +03:00
if err != nil {
2021-07-15 17:32:11 +05:30
logger . Errorf ( "Error matching constraint expressions: %v" , err )
2019-10-15 18:34:08 +03:00
return false
}
if ! matches {
2021-07-15 17:32:11 +05:30
logger . Debugf ( "Container pruned by constraint expressions: %q" , p . Constraints )
2019-10-15 18:34:08 +03:00
return false
}
if item . Status != api . HealthPassing && item . Status != api . HealthWarning {
logger . Debug ( "Filtering unhealthy or starting item" )
return false
}
return true
}
func ( p * Provider ) buildTCPServiceConfiguration ( ctx context . Context , item itemData , configuration * dynamic . TCPConfiguration ) error {
if len ( configuration . Services ) == 0 {
configuration . Services = make ( map [ string ] * dynamic . TCPService )
lb := & dynamic . TCPServersLoadBalancer { }
lb . SetDefaults ( )
2020-03-30 19:12:05 +02:00
configuration . Services [ provider . Normalize ( item . Name ) ] = & dynamic . TCPService {
2019-10-15 18:34:08 +03:00
LoadBalancer : lb ,
}
}
for name , service := range configuration . Services {
ctxSvc := log . With ( ctx , log . Str ( log . ServiceName , name ) )
err := p . addServerTCP ( ctxSvc , item , service . LoadBalancer )
if err != nil {
return err
}
}
return nil
}
2020-02-20 22:24:05 +01:00
func ( p * Provider ) buildUDPServiceConfiguration ( ctx context . Context , item itemData , configuration * dynamic . UDPConfiguration ) error {
if len ( configuration . Services ) == 0 {
configuration . Services = make ( map [ string ] * dynamic . UDPService )
lb := & dynamic . UDPServersLoadBalancer { }
2020-03-30 19:12:05 +02:00
configuration . Services [ provider . Normalize ( item . Name ) ] = & dynamic . UDPService {
2020-02-20 22:24:05 +01:00
LoadBalancer : lb ,
}
}
for name , service := range configuration . Services {
ctxSvc := log . With ( ctx , log . Str ( log . ServiceName , name ) )
err := p . addServerUDP ( ctxSvc , item , service . LoadBalancer )
if err != nil {
return err
}
}
return nil
}
2019-10-15 18:34:08 +03:00
func ( p * Provider ) buildServiceConfiguration ( ctx context . Context , item itemData , configuration * dynamic . HTTPConfiguration ) error {
if len ( configuration . Services ) == 0 {
configuration . Services = make ( map [ string ] * dynamic . Service )
lb := & dynamic . ServersLoadBalancer { }
lb . SetDefaults ( )
2020-03-30 19:12:05 +02:00
configuration . Services [ provider . Normalize ( item . Name ) ] = & dynamic . Service {
2019-10-15 18:34:08 +03:00
LoadBalancer : lb ,
}
}
for name , service := range configuration . Services {
ctxSvc := log . With ( ctx , log . Str ( log . ServiceName , name ) )
err := p . addServer ( ctxSvc , item , service . LoadBalancer )
if err != nil {
return err
}
}
return nil
}
func ( p * Provider ) addServerTCP ( ctx context . Context , item itemData , loadBalancer * dynamic . TCPServersLoadBalancer ) error {
if loadBalancer == nil {
return errors . New ( "load-balancer is not defined" )
}
2020-02-25 23:00:04 +01:00
var port string
if len ( loadBalancer . Servers ) > 0 {
port = loadBalancer . Servers [ 0 ] . Port
}
2019-10-15 18:34:08 +03:00
if len ( loadBalancer . Servers ) == 0 {
loadBalancer . Servers = [ ] dynamic . TCPServer { { } }
}
2020-02-25 23:00:04 +01:00
if item . Port != "" && port == "" {
2019-10-15 18:34:08 +03:00
port = item . Port
}
2020-02-25 23:00:04 +01:00
loadBalancer . Servers [ 0 ] . Port = ""
2019-10-15 18:34:08 +03:00
2020-02-20 22:24:05 +01:00
if port == "" {
return errors . New ( "port is missing" )
}
if item . Address == "" {
return errors . New ( "address is missing" )
}
loadBalancer . Servers [ 0 ] . Address = net . JoinHostPort ( item . Address , port )
return nil
}
func ( p * Provider ) addServerUDP ( ctx context . Context , item itemData , loadBalancer * dynamic . UDPServersLoadBalancer ) error {
if loadBalancer == nil {
return errors . New ( "load-balancer is not defined" )
}
if len ( loadBalancer . Servers ) == 0 {
loadBalancer . Servers = [ ] dynamic . UDPServer { { } }
}
var port string
if item . Port != "" {
port = item . Port
loadBalancer . Servers [ 0 ] . Port = ""
}
2019-10-15 18:34:08 +03:00
if port == "" {
return errors . New ( "port is missing" )
}
2019-11-14 11:10:06 +01:00
if item . Address == "" {
return errors . New ( "address is missing" )
}
2019-10-15 18:34:08 +03:00
loadBalancer . Servers [ 0 ] . Address = net . JoinHostPort ( item . Address , port )
return nil
}
func ( p * Provider ) addServer ( ctx context . Context , item itemData , loadBalancer * dynamic . ServersLoadBalancer ) error {
if loadBalancer == nil {
return errors . New ( "load-balancer is not defined" )
}
var port string
if len ( loadBalancer . Servers ) > 0 {
port = loadBalancer . Servers [ 0 ] . Port
}
if len ( loadBalancer . Servers ) == 0 {
server := dynamic . Server { }
server . SetDefaults ( )
loadBalancer . Servers = [ ] dynamic . Server { server }
}
2020-02-25 23:00:04 +01:00
if item . Port != "" && port == "" {
2019-10-15 18:34:08 +03:00
port = item . Port
}
2020-02-25 23:00:04 +01:00
loadBalancer . Servers [ 0 ] . Port = ""
2019-10-15 18:34:08 +03:00
if port == "" {
return errors . New ( "port is missing" )
}
2019-11-14 11:10:06 +01:00
if item . Address == "" {
return errors . New ( "address is missing" )
}
2021-07-15 17:32:11 +05:30
scheme := loadBalancer . Servers [ 0 ] . Scheme
2019-10-15 18:34:08 +03:00
loadBalancer . Servers [ 0 ] . Scheme = ""
2021-07-15 17:32:11 +05:30
if item . ExtraConf . ConsulCatalog . Connect {
loadBalancer . ServersTransport = itemServersTransportKey ( item )
scheme = "https"
}
loadBalancer . Servers [ 0 ] . URL = fmt . Sprintf ( "%s://%s" , scheme , net . JoinHostPort ( item . Address , port ) )
2019-10-15 18:34:08 +03:00
return nil
}
2021-07-15 17:32:11 +05:30
func itemServersTransportKey ( item itemData ) string {
return provider . Normalize ( "tls-" + item . Namespace + "-" + item . Datacenter + "-" + item . Name )
}