package traefik import ( "errors" "reflect" "testing" ) // TLS-Passthrough für eigene CAs (z. B. tinyCA im Kundenlabor). func caLabels() map[string]string { return map[string]string{ "traefik.enable": "true", "traefik.tcp.routers.ca.rule": "HostSNI(`ca.lab.kunde.de`)", "traefik.tcp.routers.ca.entrypoints": "websecure", "traefik.tcp.routers.ca.tls.passthrough": "true", "traefik.tcp.services.ca.loadbalancer.server.port": "9000", } } func TestFromLabels_TCPPassthrough(t *testing.T) { got, err := FromLabels("100.64.0.42", caLabels()) if err != nil { t.Fatalf("unerwarteter Fehler: %v", err) } want := &Configuration{TCP: &TCPConfiguration{ Routers: map[string]*TCPRouter{ "ca": { EntryPoints: []string{"websecure"}, Service: "ca", Rule: "HostSNI(`ca.lab.kunde.de`)", TLS: &TCPRouterTLS{Passthrough: true}, }, }, Services: map[string]*TCPService{ "ca": {LoadBalancer: &TCPServersLoadBalancer{Servers: []TCPServer{{Address: "100.64.0.42:9000"}}}}, }, }} if !reflect.DeepEqual(got, want) { t.Errorf("Konfiguration weicht ab\n got: %s\nwant: %s", mustJSON(t, got), mustJSON(t, want)) } } func TestFromLabels_TCPAttributes(t *testing.T) { l := caLabels() delete(l, "traefik.tcp.routers.ca.tls.passthrough") l["traefik.TCP.Routers.ca.TLS"] = "true" l["traefik.tcp.routers.ca.priority"] = "7" l["traefik.tcp.routers.ca.service"] = "ca" got, err := FromLabels("2001:db8::1", l) if err != nil { t.Fatalf("unerwarteter Fehler: %v", err) } r := got.TCP.Routers["ca"] if r.Priority != 7 || r.TLS == nil || r.TLS.Passthrough { t.Errorf("Router = %+v", r) } if addr := got.TCP.Services["ca"].LoadBalancer.Servers[0].Address; addr != "[2001:db8::1]:9000" { t.Errorf("Adresse = %q", addr) } } // Ohne service-Label bindet sich der Router an den einzigen TCP-Service. func TestFromLabels_TCPDefaultServiceBinding(t *testing.T) { got, err := FromLabels("10.0.0.1", caLabels()) if err != nil { t.Fatal(err) } if got.TCP.Routers["ca"].Service != "ca" { t.Errorf("Service = %q", got.TCP.Routers["ca"].Service) } } // HTTP und TCP im selben Container: getrennte Namensräume, wie bei Traefik. func TestFromLabels_HTTPAndTCPTogether(t *testing.T) { l := caLabels() l["traefik.http.routers.ca.rule"] = "Host(`ca.lab.kunde.de`)" l["traefik.http.routers.ca.entrypoints"] = "web" l["traefik.http.services.ca.loadbalancer.server.port"] = "80" got, err := FromLabels("10.0.0.1", l) if err != nil { t.Fatal(err) } if got.HTTP.Routers["ca"].Service != "ca" || got.TCP.Routers["ca"].Service != "ca" { t.Errorf("Bindung falsch: %s", mustJSON(t, got)) } } func TestFromLabels_TCPErrors(t *testing.T) { tests := map[string]struct { key, value string want error }{ "certresolver": {"traefik.tcp.routers.ca.tls.certresolver", "le", ErrUnsupportedLabel}, "middlewares": {"traefik.tcp.routers.ca.middlewares", "x", ErrUnsupportedLabel}, "tcp middlewares": {"traefik.tcp.middlewares.x.ipallowlist.sourcerange", "10.0.0.0/8", ErrUnsupportedLabel}, "proxyprotocol": {"traefik.tcp.services.ca.loadbalancer.proxyprotocol.version", "2", ErrUnsupportedLabel}, "udp": {"traefik.udp.routers.dns.entrypoints", "dns", ErrUnsupportedLabel}, "passthrough kaputt": {"traefik.tcp.routers.ca.tls.passthrough", "vielleicht", ErrInvalidLabel}, "port kaputt": {"traefik.tcp.services.ca.loadbalancer.server.port", "0", ErrInvalidLabel}, } for name, tt := range tests { t.Run(name, func(t *testing.T) { l := caLabels() l[tt.key] = tt.value if _, err := FromLabels("10.0.0.1", l); !errors.Is(err, tt.want) { t.Errorf("erwartet %v, bekommen %v", tt.want, err) } }) } l := caLabels() delete(l, "traefik.tcp.routers.ca.rule") if _, err := FromLabels("10.0.0.1", l); !errors.Is(err, ErrIncomplete) { t.Errorf("fehlende Regel: %v", err) } } func TestMerge_TCP(t *testing.T) { a, err := FromLabels("10.0.0.1", caLabels()) if err != nil { t.Fatal(err) } b, err := FromLabels("10.0.0.2", map[string]string{ "traefik.enable": "true", "traefik.tcp.routers.db.rule": "HostSNI(`db.kunde.de`)", "traefik.tcp.routers.db.tls.passthrough": "true", "traefik.tcp.services.db.loadbalancer.server.port": "5432", }) if err != nil { t.Fatal(err) } got, err := Merge(a, b, nil) if err != nil { t.Fatalf("Merge: %v", err) } if len(got.TCP.Routers) != 2 || len(got.TCP.Services) != 2 || got.HTTP != nil { t.Errorf("Ergebnis: %s", mustJSON(t, got)) } c, _ := FromLabels("10.0.0.3", caLabels()) // gleicher Name, andere Adresse if _, err := Merge(a, c); !errors.Is(err, ErrConflict) { t.Errorf("erwartet ErrConflict, bekommen %v", err) } } func TestMarshal_TCP(t *testing.T) { c, err := FromLabels("10.0.0.1", caLabels()) if err != nil { t.Fatal(err) } got, err := c.Marshal(FormatJSON) if err != nil { t.Fatal(err) } want := `{"tcp":{"routers":{"ca":{"entryPoints":["websecure"],"service":"ca","rule":"HostSNI(` + "`ca.lab.kunde.de`" + `)","tls":{"passthrough":true}}},"services":{"ca":{"loadBalancer":{"servers":[{"address":"10.0.0.1:9000"}]}}}}}` if string(got) != want { t.Errorf("JSON\n got: %s\nwant: %s", got, want) } }