Repository: allegro/marathon-consul
Pull request #210 (2017-03-14 15:07:45)

support for a path in marathon location
Hi, would you be open to adjusting the range of supported values of the marathon location parameter?

In order to join multiple marathons (e.g. per dev-team, per project) we are discovering their (semi-random) locations through linkerd (https://linkerd.io/documentation/).

This changes our --marathon-location value from the standard hostname:port into something like  --marathon-location=localhost:4141/ops-staging/marathon-devteam-1

Proposed fix checks, naively, for the existence of "path" and divides it into host  and url that is then prefixing the path param. 

coveralls: 
[![Coverage Status](https://coveralls.io/builds/10585533/badge)](https://coveralls.io/builds/10585533)

Coverage decreased (-0.09%) to 87.588% when pulling **c44e5e981a1f050846350fc0d605a3c2a8b32a51 on strzelecki-maciek:path_in_marathon_location** into **b1e8dd8d757cd83eb31f21d9e83ef5404c7de0dc on allegro:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/10625262/badge)](https://coveralls.io/builds/10625262)

Coverage decreased (-0.09%) to 87.588% when pulling **56d9d3a5bfa94b22b4c69d20ef6c5a9357b33c24 on strzelecki-maciek:path_in_marathon_location** into **b1e8dd8d757cd83eb31f21d9e83ef5404c7de0dc on allegro:master**.


Patch:
diff --git a/marathon/marathon.go b/marathon/marathon.go
index 7bf545e..93bed15 100644
--- a/marathon/marathon.go
+++ b/marathon/marathon.go
@@ -212,13 +212,28 @@ func (m Marathon) url(path string) string {
 
 type params map[string][]string
 
+// urlWithQuery returns absolute path to marathon endpoint
+// if location is given with path e.g. "localhost:8080/proxy/url", then
+// host and path parts are appended to respective url.URL fields
 func (m Marathon) urlWithQuery(path string, params params) string {
-	marathon := url.URL{
-		Scheme: m.Protocol,
-		User:   m.Auth,
-		Host:   m.Location,
-		Path:   path,
+	var marathon url.URL
+	if strings.Contains(m.Location, "/") {
+		parts := strings.SplitN(m.Location, "/", 2)
+		marathon = url.URL{
+			Scheme: m.Protocol,
+			User:   m.Auth,
+			Host:   parts[0],
+			Path:   "/" + parts[1] + path,
+		}
+	} else {
+		marathon = url.URL{
+			Scheme: m.Protocol,
+			User:   m.Auth,
+			Host:   m.Location,
+			Path:   path,
+		}
 	}
+
 	query := marathon.Query()
 	for key, values := range params {
 		for _, value := range values {


Test patch:
diff --git a/marathon/marathon_test.go b/marathon/marathon_test.go
index 8d7ae74..74976ac 100644
--- a/marathon/marathon_test.go
+++ b/marathon/marathon_test.go
@@ -408,6 +408,30 @@ func TestEventStream_PassingStreamerCreated(t *testing.T) {
 	assert.IsType(t, &Streamer{}, streamer)
 }
 
+func TestUrlWithQuery_NoProxyMarathon(t *testing.T) {
+	t.Parallel()
+
+	// given
+	m, _ := New(Config{Location: "localhost:8080", Protocol: "HTTP"}, "")
+	// when
+	path := m.urlWithQuery("/testpath", params{})
+
+	// then
+	assert.Equal(t, "HTTP://localhost:8080/testpath", path)
+}
+
+func TestUrlWithQuery_ProxyMarathon(t *testing.T) {
+	t.Parallel()
+
+	// given
+	m, _ := New(Config{Location: "localhost:8080/proxy/url/segments", Protocol: "HTTP"}, "")
+	// when
+	path := m.urlWithQuery("/testpath", params{})
+
+	// then
+	assert.Equal(t, "HTTP://localhost:8080/proxy/url/segments/testpath", path)
+}
+
 // http://keighl.com/post/mocking-http-responses-in-golang/
 func stubServer(uri string, body string) (*httptest.Server, *http.Transport) {
 	return mockServer(func(w http.ResponseWriter, r *http.Request) {