From 69361aea1b29e8bca3b5c065f526e42661b23b9c Mon Sep 17 00:00:00 2001 From: yusing Date: Sat, 21 Sep 2024 18:23:20 +0800 Subject: [PATCH] fixed host set to localhost even on remote docker, fixed one error in provider causing all routes not to load --- src/config/config.go | 16 +++++++++--- src/docker/client.go | 18 ++++++++++++-- src/proxy/fields/stream_port.go | 3 ++- src/proxy/provider/docker_provider.go | 9 +++++-- src/proxy/provider/docker_provider_test.go | 26 +++++++++++++++++-- src/proxy/provider/file_provider.go | 16 ++++++++++-- src/proxy/provider/provider.go | 29 +++++++++++++--------- src/utils/fs.go | 15 ----------- 8 files changed, 92 insertions(+), 40 deletions(-) delete mode 100644 src/utils/fs.go diff --git a/src/config/config.go b/src/config/config.go index 1e17ac7..ca0cceb 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -238,14 +238,22 @@ func (cfg *Config) loadProviders(providers *M.ProxyProviders) (res E.NestedError defer b.To(&res) for _, filename := range providers.Files { - p := PR.NewFileProvider(filename) + p, err := PR.NewFileProvider(filename) + if err != nil { + b.Add(err.Subject(filename)) + continue + } cfg.proxyProviders.Store(p.GetName(), p) - b.Add(p.LoadRoutes()) + b.Add(p.LoadRoutes().Subject(filename)) } for name, dockerHost := range providers.Docker { - p := PR.NewDockerProvider(name, dockerHost) + p, err := PR.NewDockerProvider(name, dockerHost) + if err != nil { + b.Add(err.Subject(dockerHost)) + continue + } cfg.proxyProviders.Store(p.GetName(), p) - b.Add(p.LoadRoutes()) + b.Add(p.LoadRoutes().Subject(dockerHost)) } return } diff --git a/src/docker/client.go b/src/docker/client.go index baebb3f..3fdc1c6 100644 --- a/src/docker/client.go +++ b/src/docker/client.go @@ -20,9 +20,23 @@ type Client struct { l logrus.FieldLogger } +func ParseDockerHostname(host string) (string, E.NestedError) { + if host == common.DockerHostFromEnv { + return host, nil + } else if host == "" { + return "localhost", nil + } + url, err := E.Check(client.ParseHostURL(host)) + if err != nil { + return "", E.Invalid("host", host).With(err) + } + return url.Hostname(), nil +} + func (c Client) DaemonHostname() string { - url, _ := client.ParseHostURL(c.DaemonHost()) - return url.Hostname() + // DaemonHost should always return a valid host + hostname, _ := ParseDockerHostname(c.DaemonHost()) + return hostname } func (c Client) Connected() bool { diff --git a/src/proxy/fields/stream_port.go b/src/proxy/fields/stream_port.go index f853f2c..54beccc 100644 --- a/src/proxy/fields/stream_port.go +++ b/src/proxy/fields/stream_port.go @@ -1,6 +1,7 @@ package fields import ( + "fmt" "strings" "github.com/yusing/go-proxy/common" @@ -15,7 +16,7 @@ type StreamPort struct { func ValidateStreamPort(p string) (StreamPort, E.NestedError) { split := strings.Split(p, ":") if len(split) != 2 { - return StreamPort{}, E.Invalid("stream port", p).With("should be in 'x:y' format") + return StreamPort{}, E.Invalid("stream port", fmt.Sprintf("%q", p)).With("should be in 'x:y' format") } listeningPort, err := ValidatePort(split[0]) diff --git a/src/proxy/provider/docker_provider.go b/src/proxy/provider/docker_provider.go index 64b88ed..47beb95 100755 --- a/src/proxy/provider/docker_provider.go +++ b/src/proxy/provider/docker_provider.go @@ -18,8 +18,12 @@ type DockerProvider struct { var AliasRefRegex = regexp.MustCompile(`\$\d+`) -func DockerProviderImpl(dockerHost string) ProviderImpl { - return &DockerProvider{dockerHost: dockerHost} +func DockerProviderImpl(dockerHost string) (ProviderImpl, E.NestedError) { + hostname, err := D.ParseDockerHostname(dockerHost) + if err.HasError() { + return nil, err + } + return &DockerProvider{dockerHost: dockerHost, hostname: hostname}, nil } func (p *DockerProvider) NewWatcher() W.Watcher { @@ -27,6 +31,7 @@ func (p *DockerProvider) NewWatcher() W.Watcher { } func (p *DockerProvider) LoadRoutesImpl() (routes R.Routes, err E.NestedError) { + routes = R.NewRoutes() entries := M.NewProxyEntries() info, err := D.GetClientInfo(p.dockerHost, true) diff --git a/src/proxy/provider/docker_provider_test.go b/src/proxy/provider/docker_provider_test.go index d4f5d86..61d0820 100644 --- a/src/proxy/provider/docker_provider_test.go +++ b/src/proxy/provider/docker_provider_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/docker/docker/api/types" + "github.com/yusing/go-proxy/common" D "github.com/yusing/go-proxy/docker" E "github.com/yusing/go-proxy/error" F "github.com/yusing/go-proxy/utils/functional" @@ -51,6 +52,12 @@ X_Custom_Header2: value3 Names: dummyNames, Labels: map[string]string{ D.LableAliases: "a,b", + D.LabelIdleTimeout: common.IdleTimeoutDefault, + D.LabelStopMethod: common.StopMethodDefault, + D.LabelStopSignal: "SIGTERM", + D.LabelStopTimeout: common.StopTimeoutDefault, + D.LabelWakeTimeout: common.WakeTimeoutDefault, + "proxy.*.no_tls_verify": "true", "proxy.*.scheme": "https", "proxy.*.host": "app", "proxy.*.port": "4567", @@ -73,8 +80,8 @@ X_Custom_Header2: value3 ExpectEqual(t, a.Port, "4567") ExpectEqual(t, b.Port, "4567") - ExpectEqual(t, a.NoTLSVerify, true) - ExpectEqual(t, b.NoTLSVerify, false) + ExpectTrue(t, a.NoTLSVerify) + ExpectTrue(t, b.NoTLSVerify) ExpectDeepEqual(t, a.PathPatterns, pathPatternsExpect) ExpectEqual(t, len(b.PathPatterns), 0) @@ -84,6 +91,21 @@ X_Custom_Header2: value3 ExpectDeepEqual(t, a.HideHeaders, hideHeadersExpect) ExpectEqual(t, len(b.HideHeaders), 0) + + ExpectEqual(t, a.IdleTimeout, common.IdleTimeoutDefault) + ExpectEqual(t, b.IdleTimeout, common.IdleTimeoutDefault) + + ExpectEqual(t, a.StopTimeout, common.StopTimeoutDefault) + ExpectEqual(t, b.StopTimeout, common.StopTimeoutDefault) + + ExpectEqual(t, a.StopMethod, common.StopMethodDefault) + ExpectEqual(t, b.StopMethod, common.StopMethodDefault) + + ExpectEqual(t, a.WakeTimeout, common.WakeTimeoutDefault) + ExpectEqual(t, b.WakeTimeout, common.WakeTimeoutDefault) + + ExpectEqual(t, a.StopSignal, "SIGTERM") + ExpectEqual(t, b.StopSignal, "SIGTERM") } func TestApplyLabel(t *testing.T) { diff --git a/src/proxy/provider/file_provider.go b/src/proxy/provider/file_provider.go index aeb5419..ebf6735 100644 --- a/src/proxy/provider/file_provider.go +++ b/src/proxy/provider/file_provider.go @@ -1,6 +1,7 @@ package provider import ( + "errors" "os" "path" @@ -17,11 +18,20 @@ type FileProvider struct { path string } -func FileProviderImpl(filename string) ProviderImpl { - return &FileProvider{ +func FileProviderImpl(filename string) (ProviderImpl, E.NestedError) { + impl := &FileProvider{ fileName: filename, path: path.Join(common.ConfigBasePath, filename), } + _, err := os.Stat(impl.path) + switch { + case err == nil: + return impl, nil + case errors.Is(err, os.ErrNotExist): + return nil, E.NotExist("file", impl.path) + default: + return nil, E.UnexpectedError(err) + } } func Validate(data []byte) E.NestedError { @@ -52,6 +62,8 @@ func (p FileProvider) OnEvent(event W.Event, routes R.Routes) (res EventResult) } func (p *FileProvider) LoadRoutesImpl() (routes R.Routes, res E.NestedError) { + routes = R.NewRoutes() + b := E.NewBuilder("file %q validation failure", p.fileName) defer b.To(&res) diff --git a/src/proxy/provider/provider.go b/src/proxy/provider/provider.go index a34c17d..1910c1e 100644 --- a/src/proxy/provider/provider.go +++ b/src/proxy/provider/provider.go @@ -27,6 +27,7 @@ type ( } ProviderImpl interface { NewWatcher() W.Watcher + // even returns error, routes must be non-nil LoadRoutesImpl() (R.Routes, E.NestedError) OnEvent(event W.Event, routes R.Routes) EventResult } @@ -53,19 +54,25 @@ func newProvider(name string, t ProviderType) *Provider { return p } -func NewFileProvider(filename string) *Provider { +func NewFileProvider(filename string) (p *Provider, err E.NestedError) { name := path.Base(filename) - p := newProvider(name, ProviderTypeFile) - p.ProviderImpl = FileProviderImpl(filename) + p = newProvider(name, ProviderTypeFile) + p.ProviderImpl, err = FileProviderImpl(filename) + if err != nil { + return nil, err + } p.watcher = p.NewWatcher() - return p + return } -func NewDockerProvider(name string, dockerHost string) *Provider { - p := newProvider(name, ProviderTypeDocker) - p.ProviderImpl = DockerProviderImpl(dockerHost) +func NewDockerProvider(name string, dockerHost string) (p *Provider, err E.NestedError) { + p = newProvider(name, ProviderTypeDocker) + p.ProviderImpl, err = DockerProviderImpl(dockerHost) + if err != nil { + return nil, err + } p.watcher = p.NewWatcher() - return p + return } func (p *Provider) GetName() string { @@ -137,11 +144,9 @@ func (p *Provider) GetRoute(alias string) (R.Route, bool) { func (p *Provider) LoadRoutes() E.NestedError { routes, err := p.LoadRoutesImpl() - if err != nil { - return err - } p.routes = routes - return nil + p.l.Infof("loaded %d routes", routes.Size()) + return err } func (p *Provider) watchEvents() { diff --git a/src/utils/fs.go b/src/utils/fs.go deleted file mode 100644 index f7c01dd..0000000 --- a/src/utils/fs.go +++ /dev/null @@ -1,15 +0,0 @@ -package utils - -import ( - "os" - "path" -) - -func FileOK(p string) bool { - _, err := os.Stat(p) - return err == nil -} - -func FileName(p string) string { - return path.Base(p) -} \ No newline at end of file