164 lines
5.5 KiB
Go
164 lines
5.5 KiB
Go
// Package traefik erzeugt die dynamische Traefik-Konfiguration, die der
|
|
// Sultan-Server über den HTTP-Provider (GET /v1/traefik-config) ausliefert.
|
|
//
|
|
// Die Typen bilden die Teilmenge von Traefiks "dynamic configuration" ab,
|
|
// die Sultan aus Docker-Labels bzw. /etc/sultan.d-Dateien erzeugt. Die
|
|
// Ausgabe ist JSON oder YAML; Traefiks HTTP-Provider akzeptiert beides.
|
|
package traefik
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// Configuration ist die Wurzel der dynamischen Traefik-Konfiguration.
|
|
type Configuration struct {
|
|
HTTP *HTTPConfiguration `json:"http,omitempty" yaml:"http,omitempty"`
|
|
TCP *TCPConfiguration `json:"tcp,omitempty" yaml:"tcp,omitempty"`
|
|
}
|
|
|
|
// HTTPConfiguration enthält Router, Services und Middlewares der HTTP-Ebene.
|
|
type HTTPConfiguration struct {
|
|
Routers map[string]*Router `json:"routers,omitempty" yaml:"routers,omitempty"`
|
|
Services map[string]*Service `json:"services,omitempty" yaml:"services,omitempty"`
|
|
Middlewares map[string]Middleware `json:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
|
}
|
|
|
|
// Router entspricht einem Traefik-HTTP-Router.
|
|
type Router struct {
|
|
EntryPoints []string `json:"entryPoints,omitempty" yaml:"entryPoints,omitempty"`
|
|
Middlewares []string `json:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
|
Service string `json:"service" yaml:"service"`
|
|
Rule string `json:"rule" yaml:"rule"`
|
|
Priority int `json:"priority,omitempty" yaml:"priority,omitempty"`
|
|
TLS *RouterTLS `json:"tls,omitempty" yaml:"tls,omitempty"`
|
|
}
|
|
|
|
// RouterTLS aktiviert TLS für einen Router. Ein leeres, nicht-nil RouterTLS
|
|
// wird als "tls: {}" gerendert und schaltet TLS mit Standardwerten ein.
|
|
type RouterTLS struct {
|
|
Options string `json:"options,omitempty" yaml:"options,omitempty"`
|
|
CertResolver string `json:"certResolver,omitempty" yaml:"certResolver,omitempty"`
|
|
}
|
|
|
|
// Service entspricht einem Traefik-HTTP-Service.
|
|
type Service struct {
|
|
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
|
|
}
|
|
|
|
// ServersLoadBalancer verteilt Anfragen auf die angegebenen Server.
|
|
type ServersLoadBalancer struct {
|
|
Servers []Server `json:"servers" yaml:"servers"`
|
|
PassHostHeader *bool `json:"passHostHeader,omitempty" yaml:"passHostHeader,omitempty"`
|
|
}
|
|
|
|
// Server ist ein einzelnes Backend-Ziel.
|
|
type Server struct {
|
|
URL string `json:"url" yaml:"url"`
|
|
}
|
|
|
|
// TCPConfiguration enthält Router und Services der TCP-Ebene. Sultan nutzt
|
|
// sie nur für TLS-Passthrough (Routing per SNI, TLS endet beim Backend).
|
|
type TCPConfiguration struct {
|
|
Routers map[string]*TCPRouter `json:"routers,omitempty" yaml:"routers,omitempty"`
|
|
Services map[string]*TCPService `json:"services,omitempty" yaml:"services,omitempty"`
|
|
}
|
|
|
|
// TCPRouter entspricht einem Traefik-TCP-Router.
|
|
type TCPRouter struct {
|
|
EntryPoints []string `json:"entryPoints,omitempty" yaml:"entryPoints,omitempty"`
|
|
Service string `json:"service" yaml:"service"`
|
|
Rule string `json:"rule" yaml:"rule"`
|
|
Priority int `json:"priority,omitempty" yaml:"priority,omitempty"`
|
|
TLS *TCPRouterTLS `json:"tls,omitempty" yaml:"tls,omitempty"`
|
|
}
|
|
|
|
// TCPRouterTLS aktiviert TLS für einen TCP-Router; Passthrough reicht die
|
|
// Verbindung unverändert an das Backend durch.
|
|
type TCPRouterTLS struct {
|
|
Passthrough bool `json:"passthrough,omitempty" yaml:"passthrough,omitempty"`
|
|
}
|
|
|
|
// TCPService entspricht einem Traefik-TCP-Service.
|
|
type TCPService struct {
|
|
LoadBalancer *TCPServersLoadBalancer `json:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty"`
|
|
}
|
|
|
|
// TCPServersLoadBalancer verteilt Verbindungen auf die angegebenen Server.
|
|
type TCPServersLoadBalancer struct {
|
|
Servers []TCPServer `json:"servers" yaml:"servers"`
|
|
}
|
|
|
|
// TCPServer ist ein einzelnes TCP-Backend (host:port).
|
|
type TCPServer struct {
|
|
Address string `json:"address" yaml:"address"`
|
|
}
|
|
|
|
// Middleware ist eine Traefik-Middleware als verschachtelte Map, z. B.
|
|
// {"redirectRegex": {"regex": "...", "permanent": "true"}}.
|
|
//
|
|
// Die Blattwerte bleiben die unveränderten Label-Strings. Traefik wandelt sie
|
|
// beim Einlesen genauso in Bool-, Zahl- und Listenwerte um wie Labels
|
|
// (Listen kommagetrennt), deshalb braucht Sultan nicht jeden Middleware-Typ zu
|
|
// kennen.
|
|
type Middleware map[string]any
|
|
|
|
// Format ist das Ausgabeformat der Konfiguration.
|
|
type Format string
|
|
|
|
const (
|
|
FormatJSON Format = "json"
|
|
FormatYAML Format = "yaml"
|
|
)
|
|
|
|
// ParseFormat wandelt z. B. einen Query-Parameter in ein Format um.
|
|
// Ein leerer String ergibt FormatJSON.
|
|
func ParseFormat(s string) (Format, error) {
|
|
switch strings.ToLower(strings.TrimSpace(s)) {
|
|
case "", "json":
|
|
return FormatJSON, nil
|
|
case "yaml", "yml":
|
|
return FormatYAML, nil
|
|
default:
|
|
return "", fmt.Errorf("traefik: unbekanntes Format %q", s)
|
|
}
|
|
}
|
|
|
|
// ContentType liefert den passenden HTTP-Content-Type.
|
|
func (f Format) ContentType() string {
|
|
if f == FormatYAML {
|
|
return "application/yaml"
|
|
}
|
|
return "application/json"
|
|
}
|
|
|
|
// Marshal rendert die Konfiguration im angegebenen Format. Eine nil-
|
|
// Konfiguration ergibt ein leeres Objekt, das Traefik als "keine Routen"
|
|
// akzeptiert.
|
|
func (c *Configuration) Marshal(f Format) ([]byte, error) {
|
|
if c == nil {
|
|
c = &Configuration{}
|
|
}
|
|
switch f {
|
|
case FormatJSON:
|
|
return json.Marshal(c)
|
|
case FormatYAML:
|
|
var buf bytes.Buffer
|
|
enc := yaml.NewEncoder(&buf)
|
|
enc.SetIndent(2)
|
|
if err := enc.Encode(c); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := enc.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
default:
|
|
return nil, fmt.Errorf("traefik: unbekanntes Format %q", f)
|
|
}
|
|
}
|