diff --git a/internal/docker/label.go b/internal/docker/label.go index 73de823..5a8ba6b 100644 --- a/internal/docker/label.go +++ b/internal/docker/label.go @@ -1,6 +1,9 @@ package docker import ( + "fmt" + "strings" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -13,6 +16,8 @@ func ParseLabels(labels map[string]string) (LabelMap, gperr.Error) { nestedMap := make(LabelMap) errs := gperr.NewBuilder("labels error") + ExpandWildcard(labels) + for lbl, value := range labels { parts := strutils.SplitRune(lbl, '.') if parts[0] != NSProxy { @@ -50,3 +55,32 @@ func ParseLabels(labels map[string]string) (LabelMap, gperr.Error) { return nestedMap, errs.Error() } + +func ExpandWildcard(labels map[string]string) { + aliasLabels := make([]string, 0, len(labels)) + wildcardLabels := make(map[string]string) + + for lbl, value := range labels { + parts := strings.SplitN(lbl, ".", 3) // Split into proxy, alias, rest + if parts[0] != NSProxy || len(parts) < 2 { + continue + } + alias := parts[1] // alias or wildcard alias + if alias == WildcardAlias { + delete(labels, lbl) + if len(parts) < 3 { // invalid wildcard label (no suffix) + continue + } + wildcardLabels[parts[2]] = value + } else { + // Extract just the alias part (first segment after proxy) + aliasLabels = append(aliasLabels, alias) + } + } + + for lbl, v := range wildcardLabels { + for _, alias := range aliasLabels { + labels[fmt.Sprintf("%s.%s.%s", NSProxy, alias, lbl)] = v + } + } +} diff --git a/internal/docker/label_test.go b/internal/docker/label_test.go index d5167d3..e8174e8 100644 --- a/internal/docker/label_test.go +++ b/internal/docker/label_test.go @@ -3,16 +3,38 @@ package docker_test import ( "testing" + "github.com/stretchr/testify/require" "github.com/yusing/go-proxy/internal/docker" ) +func TestExpandWildcard(t *testing.T) { + labels := map[string]string{ + "proxy.a.host": "localhost", + "proxy.b.port": "4444", + "proxy.b.scheme": "http", + "proxy.*.port": "5555", + "proxy.*.healthcheck.disable": "true", + } + + docker.ExpandWildcard(labels) + + require.Equal(t, map[string]string{ + "proxy.a.host": "localhost", + "proxy.a.port": "5555", + "proxy.a.healthcheck.disable": "true", + "proxy.b.scheme": "http", + "proxy.b.port": "5555", + "proxy.b.healthcheck.disable": "true", + }, labels) +} + func BenchmarkParseLabels(b *testing.B) { - for range b.N { + for b.Loop() { _, _ = docker.ParseLabels(map[string]string{ "proxy.a.host": "localhost", - "proxy.a.port": "4444", - "proxy.a.scheme": "http", - "proxy.a.middlewares.request.hide_headers": "X-Header1,X-Header2", + "proxy.b.port": "4444", + "proxy.*.scheme": "http", + "proxy.*.middlewares.request.hide_headers": "X-Header1,X-Header2", }) } } diff --git a/internal/route/provider/docker.go b/internal/route/provider/docker.go index 4a58cdc..7804b16 100755 --- a/internal/route/provider/docker.go +++ b/internal/route/provider/docker.go @@ -127,8 +127,6 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) m, err := docker.ParseLabels(container.Labels) errs.Add(err) - var wildcardProps docker.LabelMap - for alias, entryMapAny := range m { if len(alias) == 0 { errs.Add(gperr.New("empty alias")) @@ -150,11 +148,6 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) } } - if alias == docker.WildcardAlias { - wildcardProps = entryMap - continue - } - // check if it is an alias reference switch alias[0] { case aliasRefPrefix, aliasRefPrefixAlt: @@ -189,14 +182,6 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) routes[alias] = r } } - if wildcardProps != nil { - for _, re := range routes { - if err := serialization.MapUnmarshalValidate(wildcardProps, re); err != nil { - errs.Add(err.Subject(docker.WildcardAlias)) - break - } - } - } return routes, errs.Error() }