diff --git a/cmd/main.go b/cmd/main.go index f21e2b4..6149737 100755 --- a/cmd/main.go +++ b/cmd/main.go @@ -84,7 +84,7 @@ func main() { if err != nil { logrus.Warn(err) } - cfg := config.GetConfig() + cfg := config.GetInstance() switch args.Command { case common.CommandListConfigs: diff --git a/config.example.yml b/config.example.yml index 8bd09e3..6745a80 100644 --- a/config.example.yml +++ b/config.example.yml @@ -30,7 +30,12 @@ providers: docker: # $DOCKER_HOST implies environment variable `DOCKER_HOST` or unix:///var/run/docker.sock by default local: $DOCKER_HOST - + # explicit only mode + # only containers with explicit aliases will be proxied + # add "!" after provider name to enable explicit only mode + # + # local!: $DOCKER_HOST + # # add more docker providers if needed # for value format, see https://docs.docker.com/reference/cli/dockerd/ # diff --git a/go.mod b/go.mod index 4d5ff66..fa17780 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,6 @@ require ( ) require ( - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cloudflare/cloudflare-go v0.106.0 // indirect @@ -30,8 +29,7 @@ require ( github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/miekg/dns v1.1.62 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect @@ -40,14 +38,13 @@ require ( github.com/opencontainers/image-spec v1.1.0 // indirect github.com/ovh/go-ovh v1.6.0 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect go.opentelemetry.io/otel v1.30.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 // indirect go.opentelemetry.io/otel/metric v1.30.0 // indirect go.opentelemetry.io/otel/sdk v1.30.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect @@ -56,10 +53,6 @@ require ( golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.25.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.66.1 // indirect - google.golang.org/protobuf v1.34.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/go.sum b/go.sum index 3c7dde4..70805ac 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,7 @@ github.com/cloudflare/cloudflare-go v0.106.0 h1:q41gC5Wc1nfi0D1ZhSHokWcd9mGMbqC7 github.com/cloudflare/cloudflare-go v0.106.0/go.mod h1:pfUQ4PIG4ISI0/Mmc21Bp86UnFU0ktmPf3iTgbSL+cM= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -51,8 +52,8 @@ github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nu github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= @@ -71,14 +72,16 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/ovh/go-ovh v1.6.0 h1:ixLOwxQdzYDx296sXcgS35TOPEahJkpjMGtzPadCjQI= github.com/ovh/go-ovh v1.6.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -130,7 +133,6 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/internal/api/handler.go b/internal/api/handler.go index 2e04118..f8ea7b0 100644 --- a/internal/api/handler.go +++ b/internal/api/handler.go @@ -42,7 +42,7 @@ func NewHandler(cfg *config.Config) http.Handler { func checkHost(f http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Host != common.APIHTTPAddr { - Logger.Warnf("invalid request to API server with host: %s, expected: %s", r.Host, common.APIHTTPAddr) + Logger.Warnf("invalid request to API server with host: %s, expect %s", r.Host, common.APIHTTPAddr) w.WriteHeader(http.StatusNotFound) w.Write([]byte("invalid request")) return diff --git a/internal/config/config.go b/internal/config/config.go index 26052f8..bc28508 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -33,7 +33,7 @@ type Config struct { var instance *Config -func GetConfig() *Config { +func GetInstance() *Config { return instance } diff --git a/internal/docker/container.go b/internal/docker/container.go index d63b7e2..1dcbc9c 100644 --- a/internal/docker/container.go +++ b/internal/docker/container.go @@ -16,6 +16,7 @@ type Container struct { func FromDocker(c *types.Container, dockerHost string) (res Container) { res.Container = c + isExplicit := c.Labels[LabelAliases] != "" res.ProxyProperties = &ProxyProperties{ DockerHost: dockerHost, ContainerName: res.getName(), @@ -25,6 +26,7 @@ func FromDocker(c *types.Container, dockerHost string) (res Container) { NetworkMode: c.HostConfig.NetworkMode, Aliases: res.getAliases(), IsExcluded: U.ParseBool(res.getDeleteLabel(LabelExclude)), + IsExplicit: isExplicit, IdleTimeout: res.getDeleteLabel(LabelIdleTimeout), WakeTimeout: res.getDeleteLabel(LabelWakeTimeout), StopMethod: res.getDeleteLabel(LabelStopMethod), diff --git a/internal/docker/proxy_properties.go b/internal/docker/proxy_properties.go index ed79147..b7a68f3 100644 --- a/internal/docker/proxy_properties.go +++ b/internal/docker/proxy_properties.go @@ -13,6 +13,7 @@ type ProxyProperties struct { Aliases []string `yaml:"-" json:"aliases"` IsExcluded bool `yaml:"-" json:"is_excluded"` + IsExplicit bool `yaml:"-" json:"is_explicit"` IdleTimeout string `yaml:"-" json:"idle_timeout"` WakeTimeout string `yaml:"-" json:"wake_timeout"` StopMethod string `yaml:"-" json:"stop_method"` diff --git a/internal/models/config.go b/internal/models/config.go index aca18e9..84dca1e 100644 --- a/internal/models/config.go +++ b/internal/models/config.go @@ -3,6 +3,7 @@ package model type Config struct { Providers ProxyProviders `yaml:",flow" json:"providers"` AutoCert AutoCertConfig `yaml:",flow" json:"autocert"` + ExplicitOnly bool `yaml:"explicit_only" json:"explicit_only"` MatchDomains []string `yaml:"match_domains" json:"match_domains"` TimeoutShutdown int `yaml:"timeout_shutdown" json:"timeout_shutdown"` RedirectToHTTPS bool `yaml:"redirect_to_https" json:"redirect_to_https"` diff --git a/internal/proxy/provider/docker.go b/internal/proxy/provider/docker.go index e12ca93..6cf52f0 100755 --- a/internal/proxy/provider/docker.go +++ b/internal/proxy/provider/docker.go @@ -16,17 +16,18 @@ import ( type DockerProvider struct { dockerHost, hostname string + ExplicitOnly bool } var AliasRefRegex = regexp.MustCompile(`#\d+`) var AliasRefRegexOld = regexp.MustCompile(`\$\d+`) -func DockerProviderImpl(dockerHost string) (ProviderImpl, E.NestedError) { +func DockerProviderImpl(dockerHost string, explicitOnly bool) (ProviderImpl, E.NestedError) { hostname, err := D.ParseDockerHostname(dockerHost) if err.HasError() { return nil, err } - return &DockerProvider{dockerHost: dockerHost, hostname: hostname}, nil + return &DockerProvider{dockerHost, hostname, explicitOnly}, nil } func (p *DockerProvider) String() string { @@ -122,11 +123,12 @@ func (p *DockerProvider) OnEvent(event W.Event, routes R.Routes) (res EventResul // Returns a list of proxy entries for a container. // Always non-nil -func (p *DockerProvider) entriesFromContainerLabels(container D.Container) (M.RawEntries, E.NestedError) { - entries := M.NewProxyEntries() +func (p *DockerProvider) entriesFromContainerLabels(container D.Container) (entries M.RawEntries, _ E.NestedError) { + entries = M.NewProxyEntries() - if container.IsExcluded { - return entries, nil + if container.IsExcluded || + !container.IsExplicit && p.ExplicitOnly { + return } // init entries map for all aliases diff --git a/internal/proxy/provider/provider.go b/internal/proxy/provider/provider.go index e388261..3838d3f 100644 --- a/internal/proxy/provider/provider.go +++ b/internal/proxy/provider/provider.go @@ -56,6 +56,9 @@ func newProvider(name string, t ProviderType) *Provider { func NewFileProvider(filename string) (p *Provider, err E.NestedError) { name := path.Base(filename) + if name == "" { + return nil, E.Invalid("file name", "empty") + } p = newProvider(name, ProviderTypeFile) p.ProviderImpl, err = FileProviderImpl(filename) if err != nil { @@ -66,8 +69,17 @@ func NewFileProvider(filename string) (p *Provider, err E.NestedError) { } func NewDockerProvider(name string, dockerHost string) (p *Provider, err E.NestedError) { + if name == "" { + return nil, E.Invalid("provider name", "empty") + } + explicitOnly := false + if name[len(name)-1] == '!' { + explicitOnly = true + name = name[:len(name)-1] + } + p = newProvider(name, ProviderTypeDocker) - p.ProviderImpl, err = DockerProviderImpl(dockerHost) + p.ProviderImpl, err = DockerProviderImpl(dockerHost, explicitOnly) if err != nil { return nil, err }