support inline yaml for docker labels, serveral minor fixes

This commit is contained in:
yusing
2025-01-03 15:35:40 +08:00
parent 6e30d39b78
commit b38bff41d8
7 changed files with 248 additions and 42 deletions

View File

@@ -1,6 +1,7 @@
package provider
import (
"fmt"
"strconv"
"strings"
@@ -13,6 +14,7 @@ import (
U "github.com/yusing/go-proxy/internal/utils"
"github.com/yusing/go-proxy/internal/utils/strutils"
"github.com/yusing/go-proxy/internal/watcher"
"gopkg.in/yaml.v3"
)
type DockerProvider struct {
@@ -125,11 +127,19 @@ func (p *DockerProvider) entriesFromContainerLabels(container *docker.Container)
continue
}
var ok bool
entryMap, ok := entryMapAny.(docker.LabelMap)
if !ok {
errs.Add(E.Errorf("expect mapping, got %T", entryMap).Subject(alias))
continue
// try to deserialize to map
entryMap = make(docker.LabelMap)
yamlStr, ok := entryMapAny.(string)
if !ok {
// should not happen
panic(fmt.Errorf("invalid entry map type %T", entryMapAny))
}
if err := yaml.Unmarshal([]byte(yamlStr), &entryMap); err != nil {
errs.Add(E.From(err).Subject(alias))
continue
}
}
if alias == docker.WildcardAlias {
@@ -153,8 +163,8 @@ func (p *DockerProvider) entriesFromContainerLabels(container *docker.Container)
}
// init entry if not exist
var en *route.RawEntry
if en, ok = entries.Load(alias); !ok {
en, ok := entries.Load(alias)
if !ok {
en = &route.RawEntry{
Alias: alias,
Container: container,
@@ -171,10 +181,12 @@ func (p *DockerProvider) entriesFromContainerLabels(container *docker.Container)
}
}
if wildcardProps != nil {
entries.RangeAll(func(alias string, re *route.RawEntry) {
entries.Range(func(alias string, re *route.RawEntry) bool {
if err := U.Deserialize(wildcardProps, re); err != nil {
errs.Add(err.Subject(alias))
errs.Add(err.Subject(docker.WildcardAlias))
return false
}
return true
})
}

View File

@@ -0,0 +1,128 @@
proxy.aliases: app,app1
# style 1 - inline yaml
proxy.app: |
scheme: http
host: 10.0.0.254
port: 80
path_patterns: # Check https://pkg.go.dev/net/http#hdr-Patterns-ServeMux for syntax
- GET / # accept any GET request
- POST /auth # for /auth and /auth/* accept only POST
- GET /home/{$} # for exactly /home
healthcheck:
disabled: false
path: /
interval: 5s
load_balance:
link: app
mode: ip_hash
options:
header: X-Forwarded-For
middlewares:
cidr_whitelist:
allow:
- 127.0.0.1
- 10.0.0.0/8
status_code: 403
message: IP not allowed
hideXForwarded:
homepage:
name: Example App
icon: png/example.png
description: An example app
category: example
access_log:
buffer_size: 100
path: /var/log/example.log
filters:
status_codes:
values:
- 200-299
- 101
method:
values:
- GET
host:
values:
- example.y.z
headers:
negative: true
values:
- foo=bar
- baz
cidr:
values:
- 192.168.10.0/24
fields:
headers:
default: keep
config:
foo: redact
query:
default: drop
config:
foo: keep
cookies:
default: redact
config:
foo: keep
# style 2 - full labels and mixed
proxy.app1.scheme: http
proxy.app1.host: 10.0.0.254
proxy.app1.port: 80
proxy.app1.path_patterns:
| # Check https://pkg.go.dev/net/http#hdr-Patterns-ServeMux for syntax
GET / # accept any GET request
POST /auth # for /auth and /auth/* accept only POST
GET /home/{$} # for exactly /home
proxy.app1.healthcheck.disabled: false
proxy.app1.healthcheck.path: /
proxy.app1.healthcheck.interval: 5s
proxy.app1.load_balance.link: app
proxy.app1.load_balance.mode: ip_hash
proxy.app1.load_balance.options.header: X-Forwarded-For
proxy.app1.middlewares.cidr_whitelist: |
allow:
- 127.0.0.1
- 10.0.0.0/8
status_code: 403
message: IP not allowed
proxy.app1.middlewares.hideXForwarded:
proxy.app1.homepage.name: Example App
proxy.app1.homepage.icon: png/example.png
proxy.app1.homepage.description: An example app
proxy.app1.homepage.category: example
proxy.app1.access_log.buffer_size: 100
proxy.app1.access_log.path: /var/log/example.log
proxy.app1.access_log.filters: |
status_codes:
values:
- 200-299
- 101
method:
values:
- GET
host:
values:
- example.y.z
headers:
negative: true
values:
- foo=bar
- baz
cidr:
values:
- 192.168.10.0/24
proxy.app1.access_log.fields: |
headers:
default: keep
config:
foo: redact
query:
default: drop
config:
foo: keep
cookies:
default: redact
config:
foo: keep

View File

@@ -0,0 +1,36 @@
package provider
import (
"testing"
"github.com/docker/docker/api/types"
"github.com/yusing/go-proxy/internal/docker"
. "github.com/yusing/go-proxy/internal/utils/testing"
"gopkg.in/yaml.v3"
_ "embed"
)
//go:embed docker_labels.yaml
var testDockerLabelsYAML []byte
func TestParseDockerLabels(t *testing.T) {
var provider DockerProvider
labels := make(map[string]string)
ExpectNoError(t, yaml.Unmarshal(testDockerLabelsYAML, &labels))
routes, err := provider.entriesFromContainerLabels(
docker.FromDocker(&types.Container{
Names: []string{"container"},
Labels: labels,
State: "running",
Ports: []types.Port{
{Type: "tcp", PrivatePort: 1234, PublicPort: 1234},
},
}, "/var/run/docker.sock"),
)
ExpectNoError(t, err)
ExpectTrue(t, routes.Has("app"))
ExpectTrue(t, routes.Has("app1"))
}

View File

@@ -9,9 +9,9 @@ import (
)
//go:embed all_fields.yaml
var yaml []byte
var testAllFieldsYAML []byte
func TestFile(t *testing.T) {
_, err := validate(yaml)
_, err := validate(testAllFieldsYAML)
ExpectNoError(t, err)
}