mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-23 17:28:53 +02:00
fixed healthchecker start even if disabled, simplified label parsing
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -12,6 +11,7 @@ import (
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
"github.com/yusing/go-proxy/internal/proxy/entry"
|
||||
"github.com/yusing/go-proxy/internal/route"
|
||||
U "github.com/yusing/go-proxy/internal/utils"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
"github.com/yusing/go-proxy/internal/watcher"
|
||||
)
|
||||
@@ -22,13 +22,13 @@ type DockerProvider struct {
|
||||
l zerolog.Logger
|
||||
}
|
||||
|
||||
var (
|
||||
AliasRefRegex = regexp.MustCompile(`#\d+`)
|
||||
AliasRefRegexOld = regexp.MustCompile(`\$\d+`)
|
||||
|
||||
ErrAliasRefIndexOutOfRange = E.New("index out of range")
|
||||
const (
|
||||
aliasRefPrefix = '#'
|
||||
aliasRefPrefixAlt = '$'
|
||||
)
|
||||
|
||||
var ErrAliasRefIndexOutOfRange = E.New("index out of range")
|
||||
|
||||
func DockerProviderImpl(name, dockerHost string, explicitOnly bool) (ProviderImpl, error) {
|
||||
if dockerHost == common.DockerHostFromEnv {
|
||||
dockerHost = common.GetEnvString("DOCKER_HOST", client.DefaultDockerHost)
|
||||
@@ -114,65 +114,70 @@ func (p *DockerProvider) entriesFromContainerLabels(container *docker.Container)
|
||||
}
|
||||
|
||||
errs := E.NewBuilder("label errors")
|
||||
for key, val := range container.Labels {
|
||||
errs.Add(p.applyLabel(container, entries, key, val))
|
||||
}
|
||||
|
||||
// remove all entries that failed to fill in missing fields
|
||||
entries.RangeAll(func(_ string, re *entry.RawEntry) {
|
||||
re.FillMissingFields()
|
||||
})
|
||||
m, err := docker.ParseLabels(container.Labels)
|
||||
errs.Add(err)
|
||||
|
||||
var wildcardProps docker.LabelMap
|
||||
|
||||
for alias, entryMapAny := range m {
|
||||
if len(alias) == 0 {
|
||||
errs.Add(E.New("empty alias"))
|
||||
continue
|
||||
}
|
||||
|
||||
var ok bool
|
||||
entryMap, ok := entryMapAny.(docker.LabelMap)
|
||||
if !ok {
|
||||
errs.Add(E.Errorf("expect mapping, got %T", entryMap).Subject(alias))
|
||||
continue
|
||||
}
|
||||
|
||||
if alias == docker.WildcardAlias {
|
||||
wildcardProps = entryMap
|
||||
continue
|
||||
}
|
||||
|
||||
// check if it is an alias reference
|
||||
switch alias[0] {
|
||||
case aliasRefPrefix, aliasRefPrefixAlt:
|
||||
index, err := strutils.Atoi(alias[1:])
|
||||
if err != nil {
|
||||
errs.Add(err)
|
||||
break
|
||||
}
|
||||
if index < 1 || index > len(container.Aliases) {
|
||||
errs.Add(ErrAliasRefIndexOutOfRange.Subject(strconv.Itoa(index)))
|
||||
break
|
||||
}
|
||||
alias = container.Aliases[index-1]
|
||||
}
|
||||
|
||||
// init entry if not exist
|
||||
var en *entry.RawEntry
|
||||
if en, ok = entries.Load(alias); !ok {
|
||||
en = &entry.RawEntry{
|
||||
Alias: alias,
|
||||
Container: container,
|
||||
}
|
||||
entries.Store(alias, en)
|
||||
}
|
||||
|
||||
// deserialize map into entry object
|
||||
err := U.Deserialize(entryMap, en)
|
||||
if err != nil {
|
||||
errs.Add(err.Subject(alias))
|
||||
} else {
|
||||
entries.Store(alias, en)
|
||||
}
|
||||
}
|
||||
if wildcardProps != nil {
|
||||
entries.RangeAll(func(alias string, re *entry.RawEntry) {
|
||||
if err := U.Deserialize(wildcardProps, re); err != nil {
|
||||
errs.Add(err.Subject(alias))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return entries, errs.Error()
|
||||
}
|
||||
|
||||
func (p *DockerProvider) applyLabel(container *docker.Container, entries entry.RawEntries, key, val string) E.Error {
|
||||
lbl := docker.ParseLabel(key, val)
|
||||
if lbl.Namespace != docker.NSProxy {
|
||||
return nil
|
||||
}
|
||||
if lbl.Target == docker.WildcardAlias {
|
||||
// apply label for all aliases
|
||||
labelErrs := entries.CollectErrors(func(a string, e *entry.RawEntry) error {
|
||||
return docker.ApplyLabel(e, lbl)
|
||||
})
|
||||
if err := E.Join(labelErrs...); err != nil {
|
||||
return err.Subject(lbl.Target)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
refErrs := E.NewBuilder("alias ref errors")
|
||||
replaceIndexRef := func(ref string) string {
|
||||
index, err := strutils.Atoi(ref[1:])
|
||||
if err != nil {
|
||||
refErrs.Add(err)
|
||||
return ref
|
||||
}
|
||||
if index < 1 || index > len(container.Aliases) {
|
||||
refErrs.Add(ErrAliasRefIndexOutOfRange.Subject(strconv.Itoa(index)))
|
||||
return ref
|
||||
}
|
||||
return container.Aliases[index-1]
|
||||
}
|
||||
|
||||
lbl.Target = AliasRefRegex.ReplaceAllStringFunc(lbl.Target, replaceIndexRef)
|
||||
lbl.Target = AliasRefRegexOld.ReplaceAllStringFunc(lbl.Target, func(ref string) string {
|
||||
p.l.Warn().Msgf("%q should now be %q, old syntax will be removed in a future version", lbl, strings.ReplaceAll(lbl.String(), "$", "#"))
|
||||
return replaceIndexRef(ref)
|
||||
})
|
||||
if refErrs.HasError() {
|
||||
return refErrs.Error().Subject(lbl.String())
|
||||
}
|
||||
|
||||
en, ok := entries.Load(lbl.Target)
|
||||
if !ok {
|
||||
en = &entry.RawEntry{
|
||||
Alias: lbl.Target,
|
||||
Container: container,
|
||||
}
|
||||
entries.Store(lbl.Target, en)
|
||||
}
|
||||
|
||||
return docker.ApplyLabel(en, lbl)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestApplyLabel(t *testing.T) {
|
||||
"POST /upload/{$}",
|
||||
"GET /static",
|
||||
}
|
||||
middlewaresExpect := D.NestedLabelMap{
|
||||
middlewaresExpect := map[string]map[string]any{
|
||||
"middleware1": {
|
||||
"prop1": "value1",
|
||||
"prop2": "value2",
|
||||
@@ -55,7 +55,6 @@ func TestApplyLabel(t *testing.T) {
|
||||
"proxy.*.scheme": "https",
|
||||
"proxy.*.host": "app",
|
||||
"proxy.*.port": "4567",
|
||||
"proxy.a.no_tls_verify": "true",
|
||||
"proxy.a.path_patterns": pathPatterns,
|
||||
"proxy.a.middlewares.middleware1.prop1": "value1",
|
||||
"proxy.a.middlewares.middleware1.prop2": "value2",
|
||||
@@ -215,6 +214,21 @@ func TestDynamicAliases(t *testing.T) {
|
||||
ExpectEqual(t, raw.Port, "5678")
|
||||
}
|
||||
|
||||
func TestDisableHealthCheck(t *testing.T) {
|
||||
c := D.FromDocker(&types.Container{
|
||||
Names: dummyNames,
|
||||
State: "running",
|
||||
Labels: map[string]string{
|
||||
"proxy.a.healthcheck.disable": "true",
|
||||
"proxy.a.port": "1234",
|
||||
},
|
||||
}, client.DefaultDockerHost)
|
||||
raw, ok := E.Must(p.entriesFromContainerLabels(c)).Load("a")
|
||||
ExpectTrue(t, ok)
|
||||
|
||||
ExpectEqual(t, raw.HealthCheck, nil)
|
||||
}
|
||||
|
||||
func TestPublicIPLocalhost(t *testing.T) {
|
||||
c := D.FromDocker(&types.Container{Names: dummyNames, State: "running"}, client.DefaultDockerHost)
|
||||
raw, ok := E.Must(p.entriesFromContainerLabels(c)).Load("a")
|
||||
|
||||
Reference in New Issue
Block a user