traefik/pkg/config/runtime/runtime.go
2023-10-11 17:33:55 +02:00

246 lines
7.2 KiB
Go

package runtime
import (
"sort"
"strings"
"github.com/rs/zerolog/log"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/logs"
)
// Status of the router/service.
const (
StatusEnabled = "enabled"
StatusDisabled = "disabled"
StatusWarning = "warning"
)
// Status of the servers.
const (
StatusUp = "UP"
StatusDown = "DOWN"
)
// Configuration holds the information about the currently running traefik instance.
type Configuration struct {
Routers map[string]*RouterInfo `json:"routers,omitempty"`
Middlewares map[string]*MiddlewareInfo `json:"middlewares,omitempty"`
TCPMiddlewares map[string]*TCPMiddlewareInfo `json:"tcpMiddlewares,omitempty"`
Services map[string]*ServiceInfo `json:"services,omitempty"`
TCPRouters map[string]*TCPRouterInfo `json:"tcpRouters,omitempty"`
TCPServices map[string]*TCPServiceInfo `json:"tcpServices,omitempty"`
UDPRouters map[string]*UDPRouterInfo `json:"udpRouters,omitempty"`
UDPServices map[string]*UDPServiceInfo `json:"udpServices,omitempty"`
}
// NewConfig returns a Configuration initialized with the given conf. It never returns nil.
func NewConfig(conf dynamic.Configuration) *Configuration {
if conf.HTTP == nil && conf.TCP == nil && conf.UDP == nil {
return &Configuration{}
}
runtimeConfig := &Configuration{}
if conf.HTTP != nil {
routers := conf.HTTP.Routers
if len(routers) > 0 {
runtimeConfig.Routers = make(map[string]*RouterInfo, len(routers))
for k, v := range routers {
runtimeConfig.Routers[k] = &RouterInfo{Router: v, Status: StatusEnabled}
}
}
services := conf.HTTP.Services
if len(services) > 0 {
runtimeConfig.Services = make(map[string]*ServiceInfo, len(services))
for k, v := range services {
runtimeConfig.Services[k] = &ServiceInfo{Service: v, Status: StatusEnabled}
}
}
middlewares := conf.HTTP.Middlewares
if len(middlewares) > 0 {
runtimeConfig.Middlewares = make(map[string]*MiddlewareInfo, len(middlewares))
for k, v := range middlewares {
runtimeConfig.Middlewares[k] = &MiddlewareInfo{Middleware: v, Status: StatusEnabled}
}
}
}
if conf.TCP != nil {
if len(conf.TCP.Routers) > 0 {
runtimeConfig.TCPRouters = make(map[string]*TCPRouterInfo, len(conf.TCP.Routers))
for k, v := range conf.TCP.Routers {
runtimeConfig.TCPRouters[k] = &TCPRouterInfo{TCPRouter: v, Status: StatusEnabled}
}
}
if len(conf.TCP.Services) > 0 {
runtimeConfig.TCPServices = make(map[string]*TCPServiceInfo, len(conf.TCP.Services))
for k, v := range conf.TCP.Services {
runtimeConfig.TCPServices[k] = &TCPServiceInfo{TCPService: v, Status: StatusEnabled}
}
}
if len(conf.TCP.Middlewares) > 0 {
runtimeConfig.TCPMiddlewares = make(map[string]*TCPMiddlewareInfo, len(conf.TCP.Middlewares))
for k, v := range conf.TCP.Middlewares {
runtimeConfig.TCPMiddlewares[k] = &TCPMiddlewareInfo{TCPMiddleware: v, Status: StatusEnabled}
}
}
}
if conf.UDP != nil {
if len(conf.UDP.Routers) > 0 {
runtimeConfig.UDPRouters = make(map[string]*UDPRouterInfo, len(conf.UDP.Routers))
for k, v := range conf.UDP.Routers {
runtimeConfig.UDPRouters[k] = &UDPRouterInfo{UDPRouter: v, Status: StatusEnabled}
}
}
if len(conf.UDP.Services) > 0 {
runtimeConfig.UDPServices = make(map[string]*UDPServiceInfo, len(conf.UDP.Services))
for k, v := range conf.UDP.Services {
runtimeConfig.UDPServices[k] = &UDPServiceInfo{UDPService: v, Status: StatusEnabled}
}
}
}
return runtimeConfig
}
// PopulateUsedBy populates all the UsedBy lists of the underlying fields of r,
// based on the relations between the included services, routers, and middlewares.
func (c *Configuration) PopulateUsedBy() {
if c == nil {
return
}
for routerName, routerInfo := range c.Routers {
// lazily initialize Status in case caller forgot to do it
if routerInfo.Status == "" {
routerInfo.Status = StatusEnabled
}
providerName := getProviderName(routerName)
if providerName == "" {
log.Error().Str(logs.RouterName, routerName).Msg("Router name is not fully qualified")
continue
}
for _, midName := range routerInfo.Router.Middlewares {
fullMidName := getQualifiedName(providerName, midName)
if _, ok := c.Middlewares[fullMidName]; !ok {
continue
}
c.Middlewares[fullMidName].UsedBy = append(c.Middlewares[fullMidName].UsedBy, routerName)
}
serviceName := getQualifiedName(providerName, routerInfo.Router.Service)
if _, ok := c.Services[serviceName]; !ok {
continue
}
c.Services[serviceName].UsedBy = append(c.Services[serviceName].UsedBy, routerName)
}
for k, serviceInfo := range c.Services {
// lazily initialize Status in case caller forgot to do it
if serviceInfo.Status == "" {
serviceInfo.Status = StatusEnabled
}
sort.Strings(c.Services[k].UsedBy)
}
for midName, mid := range c.Middlewares {
// lazily initialize Status in case caller forgot to do it
if mid.Status == "" {
mid.Status = StatusEnabled
}
sort.Strings(c.Middlewares[midName].UsedBy)
}
for routerName, routerInfo := range c.TCPRouters {
// lazily initialize Status in case caller forgot to do it
if routerInfo.Status == "" {
routerInfo.Status = StatusEnabled
}
providerName := getProviderName(routerName)
if providerName == "" {
log.Error().Str(logs.RouterName, routerName).Msg("TCP router name is not fully qualified")
continue
}
serviceName := getQualifiedName(providerName, routerInfo.TCPRouter.Service)
if _, ok := c.TCPServices[serviceName]; !ok {
continue
}
c.TCPServices[serviceName].UsedBy = append(c.TCPServices[serviceName].UsedBy, routerName)
}
for k, serviceInfo := range c.TCPServices {
// lazily initialize Status in case caller forgot to do it
if serviceInfo.Status == "" {
serviceInfo.Status = StatusEnabled
}
sort.Strings(c.TCPServices[k].UsedBy)
}
for midName, mid := range c.TCPMiddlewares {
// lazily initialize Status in case caller forgot to do it
if mid.Status == "" {
mid.Status = StatusEnabled
}
sort.Strings(c.TCPMiddlewares[midName].UsedBy)
}
for routerName, routerInfo := range c.UDPRouters {
// lazily initialize Status in case caller forgot to do it
if routerInfo.Status == "" {
routerInfo.Status = StatusEnabled
}
providerName := getProviderName(routerName)
if providerName == "" {
log.Error().Str(logs.RouterName, routerName).Msg("UDP router name is not fully qualified")
continue
}
serviceName := getQualifiedName(providerName, routerInfo.UDPRouter.Service)
if _, ok := c.UDPServices[serviceName]; !ok {
continue
}
c.UDPServices[serviceName].UsedBy = append(c.UDPServices[serviceName].UsedBy, routerName)
}
for k, serviceInfo := range c.UDPServices {
// lazily initialize Status in case caller forgot to do it
if serviceInfo.Status == "" {
serviceInfo.Status = StatusEnabled
}
sort.Strings(c.UDPServices[k].UsedBy)
}
}
func getProviderName(elementName string) string {
parts := strings.Split(elementName, "@")
if len(parts) > 1 {
return parts[1]
}
return ""
}
func getQualifiedName(provider, elementName string) string {
parts := strings.Split(elementName, "@")
if len(parts) == 1 {
return elementName + "@" + provider
}
return elementName
}