From af02a411472299772c3ed33ad37bba36565a4e10 Mon Sep 17 00:00:00 2001 From: Umputun Date: Tue, 13 Apr 2021 01:52:12 -0500 Subject: [PATCH] add primitive priority order for discovered containers --- app/discovery/provider/docker.go | 8 ++++++++ app/discovery/provider/docker_test.go | 25 ++++++++++++++++++++----- app/proxy/health.go | 6 +++--- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/app/discovery/provider/docker.go b/app/discovery/provider/docker.go index 37ced26..cd469b4 100644 --- a/app/discovery/provider/docker.go +++ b/app/discovery/provider/docker.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "regexp" + "sort" "strings" "time" @@ -125,6 +126,13 @@ func (d *Docker) List() ([]discovery.URLMapper, error) { PingURL: pingURL, ProviderID: discovery.PIDocker}) } } + + // sort by len(SrcMatch) to have shorter matches after longer + // this way we can handle possible conflicts with more detailed match triggered before less detailed + + sort.Slice(res, func(i, j int) bool { + return len(res[i].SrcMatch.String()) > len(res[j].SrcMatch.String()) + }) return res, nil } diff --git a/app/discovery/provider/docker_test.go b/app/discovery/provider/docker_test.go index c70eb3d..157474c 100644 --- a/app/discovery/provider/docker_test.go +++ b/app/discovery/provider/docker_test.go @@ -14,6 +14,16 @@ func TestDocker_List(t *testing.T) { dclient := &DockerClientMock{ ListContainersFunc: func(opts dc.ListContainersOptions) ([]dc.APIContainers, error) { return []dc.APIContainers{ + {Names: []string{"c0"}, State: "running", + Networks: dc.NetworkList{ + Networks: map[string]dc.ContainerNetwork{"bridge": {IPAddress: "127.0.0.2"}}, + }, + Ports: []dc.APIPort{ + {PrivatePort: 12348}, + }, + Labels: map[string]string{"reproxy.route": "^/a/(.*)", "reproxy.dest": "/a/$1", + "reproxy.server": "example.com", "reproxy.ping": "/ping"}, + }, {Names: []string{"c1"}, State: "running", Networks: dc.NetworkList{ Networks: map[string]dc.ContainerNetwork{"bridge": {IPAddress: "127.0.0.2"}}, @@ -58,17 +68,22 @@ func TestDocker_List(t *testing.T) { d := Docker{DockerClient: dclient, Network: "bridge"} res, err := d.List() require.NoError(t, err) - require.Equal(t, 2, len(res)) + require.Equal(t, 3, len(res)) assert.Equal(t, "^/api/123/(.*)", res[0].SrcMatch.String()) assert.Equal(t, "http://127.0.0.2:12345/blah/$1", res[0].Dst) assert.Equal(t, "example.com", res[0].Server) assert.Equal(t, "http://127.0.0.2:12345/ping", res[0].PingURL) - assert.Equal(t, "^/(.*)", res[1].SrcMatch.String()) - assert.Equal(t, "http://127.0.0.3:12346/$1", res[1].Dst) - assert.Equal(t, "http://127.0.0.3:12346/ping", res[1].PingURL) - assert.Equal(t, "*", res[1].Server) + assert.Equal(t, "^/a/(.*)", res[1].SrcMatch.String()) + assert.Equal(t, "http://127.0.0.2:12348/a/$1", res[1].Dst) + assert.Equal(t, "http://127.0.0.2:12348/ping", res[1].PingURL) + assert.Equal(t, "example.com", res[1].Server) + + assert.Equal(t, "^/(.*)", res[2].SrcMatch.String()) + assert.Equal(t, "http://127.0.0.3:12346/$1", res[2].Dst) + assert.Equal(t, "http://127.0.0.3:12346/ping", res[2].PingURL) + assert.Equal(t, "*", res[2].Server) } func TestDocker_ListWithAutoAPI(t *testing.T) { diff --git a/app/proxy/health.go b/app/proxy/health.go index 65dd235..0c81fc3 100644 --- a/app/proxy/health.go +++ b/app/proxy/health.go @@ -46,12 +46,12 @@ func (h *Http) healthHandler(w http.ResponseWriter, _ *http.Request) { if err != nil { errMsg := strings.Replace(err.Error(), "\"", "", -1) log.Printf("[WARN] failed to ping for health %s, %s", m.PingURL, errMsg) - outCh <- fmt.Errorf("(%s %s) %s, %v", m.Server, m.SrcMatch.String(), m.PingURL, errMsg) + outCh <- fmt.Errorf("%s %s: %s, %v", m.Server, m.SrcMatch.String(), m.PingURL, errMsg) return } if resp.StatusCode != http.StatusOK { log.Printf("[WARN] failed ping status for health %s (%s)", m.PingURL, resp.Status) - outCh <- fmt.Errorf("(%s %s) %s, %s", m.Server, m.SrcMatch.String(), m.PingURL, resp.Status) + outCh <- fmt.Errorf("%s %s: %s, %s", m.Server, m.SrcMatch.String(), m.PingURL, resp.Status) return } }(m) @@ -86,7 +86,7 @@ func (h *Http) healthHandler(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) _, err := fmt.Fprintf(w, `{"status": "ok", "services": %d}`, valid) if err != nil { - log.Printf("[WARN] failed to send halth, %v", err) + log.Printf("[WARN] failed to send health, %v", err) } }