erste module drin.

zwischenstand: Architektur aktualisiert, TOFU implementiert,
This commit is contained in:
br committed 2026-10-01 22:22:13 +02:00
1 parent 9d5789c5d7
commit c8df9d7651
41 files changed
+6455 -36

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
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{},
}
var errs []error
for _, c := range configs {
if c == nil || c.HTTP == nil {
continue
}
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 len(errs) > 0 {
return nil, errors.Join(errs...)
}
if len(out.Routers) == 0 && len(out.Services) == 0 && len(out.Middlewares) == 0 {
return &Configuration{}, nil
}
return &Configuration{HTTP: out}, 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
}