70 lines
2.0 KiB
Go
70 lines
2.0 KiB
Go
package traefik
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
)
|
|
|
|
// ErrConflict meldet zwei unterschiedliche Definitionen unter demselben Namen.
|
|
var ErrConflict = errors.New("Namenskonflikt")
|
|
|
|
// Merge führt die Konfigurationen mehrerer Knoten zu einer zusammen.
|
|
// nil-Einträge werden übersprungen. Identische Definitionen unter demselben
|
|
// Namen sind erlaubt, unterschiedliche ergeben ErrConflict; das Vergeben
|
|
// eindeutiger Namen (z. B. pro Mandant/Knoten) ist Aufgabe des Aufrufers.
|
|
// Die Eingaben werden nicht verändert, das Ergebnis teilt sich aber die
|
|
// Router-, Service- und Middleware-Objekte mit ihnen.
|
|
func Merge(configs ...*Configuration) (*Configuration, error) {
|
|
out := &HTTPConfiguration{
|
|
Routers: map[string]*Router{},
|
|
Services: map[string]*Service{},
|
|
Middlewares: map[string]Middleware{},
|
|
}
|
|
tcp := &TCPConfiguration{
|
|
Routers: map[string]*TCPRouter{},
|
|
Services: map[string]*TCPService{},
|
|
}
|
|
var errs []error
|
|
for _, c := range configs {
|
|
if c == nil {
|
|
continue
|
|
}
|
|
if c.HTTP != nil {
|
|
errs = append(errs, mergeInto(out.Routers, c.HTTP.Routers, "router")...)
|
|
errs = append(errs, mergeInto(out.Services, c.HTTP.Services, "service")...)
|
|
errs = append(errs, mergeInto(out.Middlewares, c.HTTP.Middlewares, "middleware")...)
|
|
}
|
|
if c.TCP != nil {
|
|
errs = append(errs, mergeInto(tcp.Routers, c.TCP.Routers, "tcp router")...)
|
|
errs = append(errs, mergeInto(tcp.Services, c.TCP.Services, "tcp service")...)
|
|
}
|
|
}
|
|
if len(errs) > 0 {
|
|
return nil, errors.Join(errs...)
|
|
}
|
|
res := &Configuration{}
|
|
if len(out.Routers) > 0 || len(out.Services) > 0 || len(out.Middlewares) > 0 {
|
|
res.HTTP = out
|
|
}
|
|
if len(tcp.Routers) > 0 || len(tcp.Services) > 0 {
|
|
res.TCP = tcp
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func mergeInto[V any](dst, src map[string]V, kind string) []error {
|
|
var errs []error
|
|
for name, v := range src {
|
|
existing, ok := dst[name]
|
|
if !ok {
|
|
dst[name] = v
|
|
continue
|
|
}
|
|
if !reflect.DeepEqual(existing, v) {
|
|
errs = append(errs, fmt.Errorf("%s %q: %w", kind, name, ErrConflict))
|
|
}
|
|
}
|
|
return errs
|
|
}
|