fix(label): expand wildcard labels before unmarshaling and add corresponding test

This commit is contained in:
yusing 2025-06-09 20:46:39 +08:00
parent 421aaecba4
commit 25fbcc4ab9
3 changed files with 60 additions and 19 deletions

View file

@ -1,6 +1,9 @@
package docker package docker
import ( import (
"fmt"
"strings"
"github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/utils/strutils" "github.com/yusing/go-proxy/internal/utils/strutils"
) )
@ -13,6 +16,8 @@ func ParseLabels(labels map[string]string) (LabelMap, gperr.Error) {
nestedMap := make(LabelMap) nestedMap := make(LabelMap)
errs := gperr.NewBuilder("labels error") errs := gperr.NewBuilder("labels error")
ExpandWildcard(labels)
for lbl, value := range labels { for lbl, value := range labels {
parts := strutils.SplitRune(lbl, '.') parts := strutils.SplitRune(lbl, '.')
if parts[0] != NSProxy { if parts[0] != NSProxy {
@ -50,3 +55,32 @@ func ParseLabels(labels map[string]string) (LabelMap, gperr.Error) {
return nestedMap, errs.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
}
}
}

View file

@ -3,16 +3,38 @@ package docker_test
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/yusing/go-proxy/internal/docker" "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) { func BenchmarkParseLabels(b *testing.B) {
for range b.N { for b.Loop() {
_, _ = docker.ParseLabels(map[string]string{ _, _ = docker.ParseLabels(map[string]string{
"proxy.a.host": "localhost", "proxy.a.host": "localhost",
"proxy.a.port": "4444", "proxy.b.port": "4444",
"proxy.a.scheme": "http", "proxy.*.scheme": "http",
"proxy.a.middlewares.request.hide_headers": "X-Header1,X-Header2", "proxy.*.middlewares.request.hide_headers": "X-Header1,X-Header2",
}) })
} }
} }

View file

@ -127,8 +127,6 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container)
m, err := docker.ParseLabels(container.Labels) m, err := docker.ParseLabels(container.Labels)
errs.Add(err) errs.Add(err)
var wildcardProps docker.LabelMap
for alias, entryMapAny := range m { for alias, entryMapAny := range m {
if len(alias) == 0 { if len(alias) == 0 {
errs.Add(gperr.New("empty alias")) 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 // check if it is an alias reference
switch alias[0] { switch alias[0] {
case aliasRefPrefix, aliasRefPrefixAlt: case aliasRefPrefix, aliasRefPrefixAlt:
@ -189,14 +182,6 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container)
routes[alias] = r 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() return routes, errs.Error()
} }