2019-08-14 15:28:04 +00:00
|
|
|
package runtime
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-02-07 16:14:07 +00:00
|
|
|
"errors"
|
2019-08-29 10:38:04 +00:00
|
|
|
"fmt"
|
2023-08-16 15:50:06 +00:00
|
|
|
"slices"
|
2019-09-02 09:38:04 +00:00
|
|
|
"sort"
|
2019-08-14 15:28:04 +00:00
|
|
|
"sync"
|
|
|
|
|
2022-11-21 17:36:05 +00:00
|
|
|
"github.com/rs/zerolog/log"
|
2023-02-03 14:24:05 +00:00
|
|
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/logs"
|
2019-08-14 15:28:04 +00:00
|
|
|
)
|
|
|
|
|
2019-09-02 09:38:04 +00:00
|
|
|
// GetRoutersByEntryPoints returns all the http routers by entry points name and routers name.
|
2019-08-14 15:28:04 +00:00
|
|
|
func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*RouterInfo {
|
|
|
|
entryPointsRouters := make(map[string]map[string]*RouterInfo)
|
|
|
|
|
|
|
|
for rtName, rt := range c.Routers {
|
|
|
|
if (tls && rt.TLS == nil) || (!tls && rt.TLS != nil) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-11-21 17:36:05 +00:00
|
|
|
logger := log.Ctx(ctx).With().Str(logs.RouterName, rtName).Logger()
|
2019-09-02 09:38:04 +00:00
|
|
|
|
2019-08-29 10:38:04 +00:00
|
|
|
entryPointsCount := 0
|
2020-03-05 11:46:05 +00:00
|
|
|
for _, entryPointName := range rt.EntryPoints {
|
2023-08-16 15:50:06 +00:00
|
|
|
if !slices.Contains(entryPoints, entryPointName) {
|
2019-08-29 10:38:04 +00:00
|
|
|
rt.AddError(fmt.Errorf("entryPoint %q doesn't exist", entryPointName), false)
|
2022-11-21 17:36:05 +00:00
|
|
|
logger.Error().Str(logs.EntryPointName, entryPointName).
|
|
|
|
Msg("EntryPoint doesn't exist")
|
2019-08-14 15:28:04 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := entryPointsRouters[entryPointName]; !ok {
|
|
|
|
entryPointsRouters[entryPointName] = make(map[string]*RouterInfo)
|
|
|
|
}
|
|
|
|
|
2019-09-02 09:38:04 +00:00
|
|
|
entryPointsCount++
|
|
|
|
rt.Using = append(rt.Using, entryPointName)
|
|
|
|
|
2019-08-14 15:28:04 +00:00
|
|
|
entryPointsRouters[entryPointName][rtName] = rt
|
|
|
|
}
|
2019-09-02 09:38:04 +00:00
|
|
|
|
2019-08-29 10:38:04 +00:00
|
|
|
if entryPointsCount == 0 {
|
2024-02-07 16:14:07 +00:00
|
|
|
rt.AddError(errors.New("no valid entryPoint for this router"), true)
|
2022-11-21 17:36:05 +00:00
|
|
|
logger.Error().Msg("No valid entryPoint for this router")
|
2019-08-29 10:38:04 +00:00
|
|
|
}
|
2019-09-02 09:38:04 +00:00
|
|
|
|
|
|
|
rt.Using = unique(rt.Using)
|
2019-08-14 15:28:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return entryPointsRouters
|
|
|
|
}
|
|
|
|
|
2019-09-02 09:38:04 +00:00
|
|
|
func unique(src []string) []string {
|
|
|
|
var uniq []string
|
|
|
|
|
|
|
|
set := make(map[string]struct{})
|
|
|
|
for _, v := range src {
|
|
|
|
if _, exist := set[v]; !exist {
|
|
|
|
set[v] = struct{}{}
|
|
|
|
uniq = append(uniq, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(uniq)
|
|
|
|
|
|
|
|
return uniq
|
|
|
|
}
|
|
|
|
|
|
|
|
// RouterInfo holds information about a currently running HTTP router.
|
2019-08-14 15:28:04 +00:00
|
|
|
type RouterInfo struct {
|
|
|
|
*dynamic.Router // dynamic configuration
|
|
|
|
// Err contains all the errors that occurred during router's creation.
|
|
|
|
Err []string `json:"error,omitempty"`
|
|
|
|
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
|
|
|
// If not in "enabled" state, the reason for it should be in the list of Err.
|
|
|
|
// It is the caller's responsibility to set the initial status.
|
2019-09-02 09:38:04 +00:00
|
|
|
Status string `json:"status,omitempty"`
|
|
|
|
Using []string `json:"using,omitempty"` // Effective entry points used by that router.
|
2019-08-14 15:28:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// AddError adds err to r.Err, if it does not already exist.
|
|
|
|
// If critical is set, r is marked as disabled.
|
|
|
|
func (r *RouterInfo) AddError(err error, critical bool) {
|
|
|
|
for _, value := range r.Err {
|
|
|
|
if value == err.Error() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r.Err = append(r.Err, err.Error())
|
|
|
|
if critical {
|
|
|
|
r.Status = StatusDisabled
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// only set it to "warning" if not already in a worse state
|
|
|
|
if r.Status != StatusDisabled {
|
|
|
|
r.Status = StatusWarning
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-02 09:38:04 +00:00
|
|
|
// MiddlewareInfo holds information about a currently running middleware.
|
2019-08-14 15:28:04 +00:00
|
|
|
type MiddlewareInfo struct {
|
|
|
|
*dynamic.Middleware // dynamic configuration
|
|
|
|
// Err contains all the errors that occurred during service creation.
|
|
|
|
Err []string `json:"error,omitempty"`
|
|
|
|
Status string `json:"status,omitempty"`
|
2019-09-02 09:38:04 +00:00
|
|
|
UsedBy []string `json:"usedBy,omitempty"` // list of routers and services using that middleware.
|
2019-08-14 15:28:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// AddError adds err to s.Err, if it does not already exist.
|
|
|
|
// If critical is set, m is marked as disabled.
|
|
|
|
func (m *MiddlewareInfo) AddError(err error, critical bool) {
|
|
|
|
for _, value := range m.Err {
|
|
|
|
if value == err.Error() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m.Err = append(m.Err, err.Error())
|
|
|
|
if critical {
|
|
|
|
m.Status = StatusDisabled
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// only set it to "warning" if not already in a worse state
|
|
|
|
if m.Status != StatusDisabled {
|
|
|
|
m.Status = StatusWarning
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-02 09:38:04 +00:00
|
|
|
// ServiceInfo holds information about a currently running service.
|
2019-08-14 15:28:04 +00:00
|
|
|
type ServiceInfo struct {
|
|
|
|
*dynamic.Service // dynamic configuration
|
|
|
|
// Err contains all the errors that occurred during service creation.
|
|
|
|
Err []string `json:"error,omitempty"`
|
|
|
|
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
|
|
|
|
// If not in "enabled" state, the reason for it should be in the list of Err.
|
|
|
|
// It is the caller's responsibility to set the initial status.
|
|
|
|
Status string `json:"status,omitempty"`
|
|
|
|
UsedBy []string `json:"usedBy,omitempty"` // list of routers using that service
|
|
|
|
|
|
|
|
serverStatusMu sync.RWMutex
|
|
|
|
serverStatus map[string]string // keyed by server URL
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddError adds err to s.Err, if it does not already exist.
|
|
|
|
// If critical is set, s is marked as disabled.
|
|
|
|
func (s *ServiceInfo) AddError(err error, critical bool) {
|
|
|
|
for _, value := range s.Err {
|
|
|
|
if value == err.Error() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Err = append(s.Err, err.Error())
|
|
|
|
if critical {
|
|
|
|
s.Status = StatusDisabled
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// only set it to "warning" if not already in a worse state
|
|
|
|
if s.Status != StatusDisabled {
|
|
|
|
s.Status = StatusWarning
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateServerStatus sets the status of the server in the ServiceInfo.
|
|
|
|
// It is the responsibility of the caller to check that s is not nil.
|
2020-07-07 12:42:03 +00:00
|
|
|
func (s *ServiceInfo) UpdateServerStatus(server, status string) {
|
2019-08-14 15:28:04 +00:00
|
|
|
s.serverStatusMu.Lock()
|
|
|
|
defer s.serverStatusMu.Unlock()
|
|
|
|
|
|
|
|
if s.serverStatus == nil {
|
|
|
|
s.serverStatus = make(map[string]string)
|
|
|
|
}
|
|
|
|
s.serverStatus[server] = status
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetAllStatus returns all the statuses of all the servers in ServiceInfo.
|
2020-05-11 10:06:07 +00:00
|
|
|
// It is the responsibility of the caller to check that s is not nil.
|
2019-08-14 15:28:04 +00:00
|
|
|
func (s *ServiceInfo) GetAllStatus() map[string]string {
|
|
|
|
s.serverStatusMu.RLock()
|
|
|
|
defer s.serverStatusMu.RUnlock()
|
|
|
|
|
|
|
|
if len(s.serverStatus) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
allStatus := make(map[string]string, len(s.serverStatus))
|
|
|
|
for k, v := range s.serverStatus {
|
|
|
|
allStatus[k] = v
|
|
|
|
}
|
|
|
|
return allStatus
|
|
|
|
}
|