From 84076db78ef9f3a92ebf822485d46100236a1907 Mon Sep 17 00:00:00 2001 From: Fabrice CLAEYS Date: Mon, 6 Jun 2016 09:21:00 +0200 Subject: [PATCH 1/8] allow multiple rules --- rules.go | 74 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/rules.go b/rules.go index e6b299d86..94f0b17f4 100644 --- a/rules.go +++ b/rules.go @@ -109,39 +109,53 @@ func (r *Rules) Parse(expression string) (*mux.Route, error) { f := func(c rune) bool { return c == ':' } - // get function - parsedFunctions := strings.FieldsFunc(expression, f) - if len(parsedFunctions) == 0 { - return nil, errors.New("Error parsing rule: " + expression) - } - parsedFunction, ok := functions[parsedFunctions[0]] - if !ok { - return nil, errors.New("Error parsing rule: " + expression + ". Unknown function: " + parsedFunctions[0]) - } - parsedFunctions = append(parsedFunctions[:0], parsedFunctions[1:]...) - fargs := func(c rune) bool { - return c == ',' || c == ';' - } - // get function - parsedArgs := strings.FieldsFunc(strings.Join(parsedFunctions, ":"), fargs) - if len(parsedArgs) == 0 { - return nil, errors.New("Error parsing args from rule: " + expression) + + // Allow multiple rules separated by ; + splitRule := func(c rune) bool { + return c == ';' } - inputs := make([]reflect.Value, len(parsedArgs)) - for i := range parsedArgs { - inputs[i] = reflect.ValueOf(parsedArgs[i]) - } - method := reflect.ValueOf(parsedFunction) - if method.IsValid() { - resultRoute := method.Call(inputs)[0].Interface().(*mux.Route) - if r.err != nil { - return nil, r.err + parsedRules := strings.FieldsFunc(expression, splitRule) + + var resultRoute *mux.Route + + for _, rule := range parsedRules { + // get function + parsedFunctions := strings.FieldsFunc(rule, f) + if len(parsedFunctions) == 0 { + return nil, errors.New("Error parsing rule: " + rule) } - if resultRoute.GetError() != nil { - return nil, resultRoute.GetError() + parsedFunction, ok := functions[parsedFunctions[0]] + if !ok { + return nil, errors.New("Error parsing rule: " + rule + ". Unknown function: " + parsedFunctions[0]) + } + parsedFunctions = append(parsedFunctions[:0], parsedFunctions[1:]...) + fargs := func(c rune) bool { + return c == ',' + } + // get function + parsedArgs := strings.FieldsFunc(strings.Join(parsedFunctions, ":"), fargs) + if len(parsedArgs) == 0 { + return nil, errors.New("Error parsing args from rule: " + rule) + } + + inputs := make([]reflect.Value, len(parsedArgs)) + for i := range parsedArgs { + inputs[i] = reflect.ValueOf(parsedArgs[i]) + } + method := reflect.ValueOf(parsedFunction) + if method.IsValid() { + resultRoute = method.Call(inputs)[0].Interface().(*mux.Route) + if r.err != nil { + return nil, r.err + } + if resultRoute.GetError() != nil { + return nil, resultRoute.GetError() + } + + } else { + return nil, errors.New("Method not found: " + parsedFunctions[0]) } - return resultRoute, nil } - return nil, errors.New("Method not found: " + parsedFunctions[0]) + return resultRoute, nil } From 78dc28cce84b72a3662e52f6d2b027cc3e284716 Mon Sep 17 00:00:00 2001 From: Fabrice CLAEYS Date: Mon, 6 Jun 2016 15:27:16 +0200 Subject: [PATCH 2/8] test rules parsing --- rules_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 rules_test.go diff --git a/rules_test.go b/rules_test.go new file mode 100644 index 000000000..cb555a4f3 --- /dev/null +++ b/rules_test.go @@ -0,0 +1,53 @@ +package main + +import ( + "github.com/gorilla/mux" + "net/http" + "testing" +) + +func TestParseOneRule(t *testing.T) { + + router := mux.NewRouter() + route := router.NewRoute() + serverRoute := &serverRoute{route: route} + rules := &Rules{route: serverRoute} + + expression := "Host:foo.bar" + routeResult, err := rules.Parse(expression) + + if err != nil { + t.Fatal("Error while building route for Host:foo.bar") + } + + request, err := http.NewRequest("GET", "http://foo.bar", nil) + routeMatch := routeResult.Match(request, &mux.RouteMatch{Route: routeResult}) + + if routeMatch == false { + t.Log(err) + t.Fatal("Rule Host:foo.bar don't match") + } +} + +func TestParseTwoRules(t *testing.T) { + + router := mux.NewRouter() + route := router.NewRoute() + serverRoute := &serverRoute{route: route} + rules := &Rules{route: serverRoute} + + expression := "Host:foo.bar;Path:/foobar" + routeResult, err := rules.Parse(expression) + + if err != nil { + t.Fatal("Error while building route for Host:foo.bar;Path:/foobar") + } + + request, err := http.NewRequest("GET", "http://foo.bar/foobar", nil) + routeMatch := routeResult.Match(request, &mux.RouteMatch{Route: routeResult}) + + if routeMatch == false { + t.Log(err) + t.Fatal("Rule Host:foo.bar;Path:/foobar don't match") + } +} From eccb5296058e2d4d39fab508ed2a82ce2ccc9103 Mon Sep 17 00:00:00 2001 From: Fabrice CLAEYS Date: Mon, 6 Jun 2016 16:07:21 +0200 Subject: [PATCH 3/8] update docs --- docs/basics.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/basics.md b/docs/basics.md index 73d9089ac..2b6331824 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -69,6 +69,8 @@ Frontends can be defined using the following rules: - `PathPrefix`: PathPrefix adds a matcher for the URL path prefixes. This matches if the given template is a prefix of the full URL path. - `PathPrefixStrip`: Same as `PathPrefix` but strip the given prefix from the request URL's Path. +You can use multiple rules by separating them by `;` + You can optionally enable `passHostHeader` to forward client `Host` header to the backend. Here is an example of frontends definition: @@ -87,13 +89,13 @@ Here is an example of frontends definition: rule = "Host: localhost, {subdomain:[a-z]+}.localhost" [frontends.frontend3] backend = "backend2" - rule = "Path:/test" + rule = "Host: test3.localhost;Path:/test" ``` - Three frontends are defined: `frontend1`, `frontend2` and `frontend3` - `frontend1` will forward the traffic to the `backend2` if the rule `Host: test.localhost, test2.localhost` is matched - `frontend2` will forward the traffic to the `backend1` if the rule `Host: localhost, {subdomain:[a-z]+}.localhost` is matched (forwarding client `Host` header to the backend) -- `frontend3` will forward the traffic to the `backend2` if the rule `Path:/test` is matched +- `frontend3` will forward the traffic to the `backend2` if the rules `Host: test3.localhost` and `Path:/test` are matched ## Backends From 208998972ac6fa710c48cc399bf9abfd6d9d4008 Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Fri, 3 Jun 2016 17:58:33 +0200 Subject: [PATCH 4/8] Add routes priorities Signed-off-by: Emile Vauge --- glide.lock | 16 ++++++++-------- glide.yaml | 2 +- middlewares/handlerSwitcher.go | 2 +- middlewares/routes.go | 2 +- rules.go | 2 +- server.go | 10 +++++++++- traefik.go | 2 +- types/types.go | 1 + web.go | 2 +- 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/glide.lock b/glide.lock index 05374f993..8c5a483df 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: dc59755b72e71945a21135c5a37e4a5c11ae511ac7404d1440166ea0aed736c4 -updated: 2016-06-02T15:11:52.77657652+02:00 +hash: 5a6dbc30a69abd002736bd5113e0f783c448faee20a0791c724ec2c3c1cfb8bb +updated: 2016-06-03T18:11:43.839017153+02:00 imports: - name: github.com/boltdb/bolt version: dfb21201d9270c1082d5fb0f07f500311ff72f18 @@ -16,9 +16,11 @@ imports: - name: github.com/codegangsta/cli version: bf4a526f48af7badd25d2cb02d587e1b01be3b50 - name: github.com/codegangsta/negroni - version: fb7b7c045dfb05dc81a5c3688c568550b5bd6e36 + version: feacfc52d357c844f524c794947493483ed881b3 - name: github.com/containous/flaeg version: b98687da5c323650f4513fda6b6203fcbdec9313 +- name: github.com/containous/mux + version: a819b77bba13f0c0cbe36e437bc2e948411b3996 - name: github.com/containous/oxy version: 183212964e13e7b8afe01a08b193d04300554a68 subpackages: @@ -43,7 +45,7 @@ imports: subpackages: - spew - name: github.com/docker/distribution - version: bb330cd684eb4afab9cc4f2453d7c8918099d7ee + version: feddf6cd4e439577ab270d8e3ba63a5d7c5c0d55 subpackages: - reference - digest @@ -100,10 +102,8 @@ imports: - query - name: github.com/gorilla/context version: aed02d124ae4a0e94fea4541c8effd05bf0c8296 -- name: github.com/gorilla/mux - version: bd09be08ed4377796d312df0a45314e11b8f5dc1 - name: github.com/hashicorp/consul - version: ebf7ea1d759184c02a5bb5263a7c52d29838ffc3 + version: 802b29ab948dedb7f7b1b903f535bdf250388c50 subpackages: - api - name: github.com/hashicorp/go-cleanhttp @@ -136,7 +136,7 @@ imports: - name: github.com/ogier/pflag version: 45c278ab3607870051a2ea9040bb85fcb8557481 - name: github.com/opencontainers/runc - version: 6c485e6902bb9dd77b8234042b8f00e20ef87a18 + version: 3211c9f721237f55a16da9c111e3d7e8777e53b5 subpackages: - libcontainer/user - name: github.com/parnurzeal/gorequest diff --git a/glide.yaml b/glide.yaml index 9a1e4385c..7668dac10 100644 --- a/glide.yaml +++ b/glide.yaml @@ -40,7 +40,7 @@ import: - package: github.com/elazarl/go-bindata-assetfs - package: github.com/gambol99/go-marathon version: ade11d1dc2884ee1f387078fc28509559b6235d1 -- package: github.com/gorilla/mux +- package: github.com/containous/mux - package: github.com/hashicorp/consul subpackages: - api diff --git a/middlewares/handlerSwitcher.go b/middlewares/handlerSwitcher.go index 81dfacd58..b9a0903e2 100644 --- a/middlewares/handlerSwitcher.go +++ b/middlewares/handlerSwitcher.go @@ -1,8 +1,8 @@ package middlewares import ( + "github.com/containous/mux" "github.com/containous/traefik/safe" - "github.com/gorilla/mux" "net/http" ) diff --git a/middlewares/routes.go b/middlewares/routes.go index 991d3085d..4f017fce0 100644 --- a/middlewares/routes.go +++ b/middlewares/routes.go @@ -5,7 +5,7 @@ import ( "log" "net/http" - "github.com/gorilla/mux" + "github.com/containous/mux" ) // Routes holds the gorilla mux routes (for the API & co). diff --git a/rules.go b/rules.go index 94f0b17f4..b14243b26 100644 --- a/rules.go +++ b/rules.go @@ -2,7 +2,7 @@ package main import ( "errors" - "github.com/gorilla/mux" + "github.com/containous/mux" "net" "net/http" "reflect" diff --git a/server.go b/server.go index 14694efbe..ecac8c4db 100644 --- a/server.go +++ b/server.go @@ -20,6 +20,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/codegangsta/negroni" + "github.com/containous/mux" "github.com/containous/oxy/cbreaker" "github.com/containous/oxy/connlimit" "github.com/containous/oxy/forward" @@ -30,7 +31,6 @@ import ( "github.com/containous/traefik/provider" "github.com/containous/traefik/safe" "github.com/containous/traefik/types" - "github.com/gorilla/mux" "github.com/mailgun/manners" "github.com/streamrail/concurrent-map" ) @@ -501,6 +501,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo } else { log.Debugf("Reusing backend %s", frontend.Backend) } + if frontend.Priority > 0 { + newServerRoute.route.Priority(frontend.Priority) + } server.wireFrontendBackend(newServerRoute, backends[frontend.Backend]) } err := newServerRoute.route.GetError() @@ -511,6 +514,10 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo } } middlewares.SetBackend2FrontendMap(&backend2FrontendMap) + //sort routes + for _, serverEntryPoint := range serverEntryPoints { + serverEntryPoint.httpRouter.GetHandler().SortRoutes() + } return serverEntryPoints, nil } @@ -576,6 +583,7 @@ func getRoute(serverRoute *serverRoute, route *types.Route) error { if err != nil { return err } + newRoute.Priority(serverRoute.route.GetPriority() + len(route.Rule)) serverRoute.route = newRoute return nil } diff --git a/traefik.go b/traefik.go index a8be2edd1..f870cffd4 100644 --- a/traefik.go +++ b/traefik.go @@ -103,7 +103,7 @@ Complete documentation is available at https://traefik.io`, s.AddSource(toml) s.AddSource(f) if _, err := s.LoadConfig(); err != nil { - fmtlog.Println(err) + fmtlog.Println(fmt.Errorf("Error reading TOML config file %s : %s", toml.ConfigFileUsed(), err)) } traefikConfiguration.ConfigFile = toml.ConfigFileUsed() diff --git a/types/types.go b/types/types.go index dcac6bd46..7d521ed23 100644 --- a/types/types.go +++ b/types/types.go @@ -52,6 +52,7 @@ type Frontend struct { Backend string `json:"backend,omitempty"` Routes map[string]Route `json:"routes,omitempty"` PassHostHeader bool `json:"passHostHeader,omitempty"` + Priority int `json:"priority,omitempty"` } // LoadBalancerMethod holds the method of load balancing to use. diff --git a/web.go b/web.go index 690c2ecfc..048ffa121 100644 --- a/web.go +++ b/web.go @@ -9,11 +9,11 @@ import ( "runtime" log "github.com/Sirupsen/logrus" + "github.com/containous/mux" "github.com/containous/traefik/autogen" "github.com/containous/traefik/safe" "github.com/containous/traefik/types" "github.com/elazarl/go-bindata-assetfs" - "github.com/gorilla/mux" "github.com/thoas/stats" "github.com/unrolled/render" ) From 287b3ba1f44a1ab7910649cffc0dda3befd21f1e Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Mon, 6 Jun 2016 14:54:45 +0200 Subject: [PATCH 5/8] Add routes priorities test Signed-off-by: Emile Vauge --- rules_test.go | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/rules_test.go b/rules_test.go index cb555a4f3..bac10e07d 100644 --- a/rules_test.go +++ b/rules_test.go @@ -1,7 +1,7 @@ package main import ( - "github.com/gorilla/mux" + "github.com/containous/mux" "net/http" "testing" ) @@ -51,3 +51,83 @@ func TestParseTwoRules(t *testing.T) { t.Fatal("Rule Host:foo.bar;Path:/foobar don't match") } } + + +func TestPriorites(t *testing.T) { + router := mux.NewRouter() + router.StrictSlash(true) + rules := &Rules{route: &serverRoute{route: router.NewRoute()}} + routeFoo, err := rules.Parse("PathPrefix:/foo") + if err != nil { + t.Fatal("Error while building route for PathPrefix:/foo") + } + fooHandler := &fakeHandler{name: "fooHandler"} + routeFoo.Handler(fooHandler) + + if !router.Match(&http.Request{URL: &url.URL{ + Path: "/foo", + }}, &mux.RouteMatch{}) { + t.Fatalf("Error matching route") + } + + if router.Match(&http.Request{URL: &url.URL{ + Path: "/fo", + }}, &mux.RouteMatch{}) { + t.Fatalf("Error matching route") + } + + multipleRules := &Rules{route: &serverRoute{route: router.NewRoute()}} + routeFoobar, err := multipleRules.Parse("PathPrefix:/foobar") + if err != nil { + t.Fatal("Error while building route for PathPrefix:/foobar") + } + foobarHandler := &fakeHandler{name: "foobarHandler"} + routeFoobar.Handler(foobarHandler) + if !router.Match(&http.Request{URL: &url.URL{ + Path: "/foo", + }}, &mux.RouteMatch{}) { + t.Fatalf("Error matching route") + } + fooMatcher := &mux.RouteMatch{} + if !router.Match(&http.Request{URL: &url.URL{ + Path: "/foobar", + }}, fooMatcher) { + t.Fatalf("Error matching route") + } + + if fooMatcher.Handler == foobarHandler { + t.Fatalf("Error matching priority") + } + + if fooMatcher.Handler != fooHandler { + t.Fatalf("Error matching priority") + } + + routeFoo.Priority(1) + routeFoobar.Priority(10) + router.SortRoutes() + + foobarMatcher := &mux.RouteMatch{} + if !router.Match(&http.Request{URL: &url.URL{ + Path: "/foobar", + }}, foobarMatcher) { + t.Fatalf("Error matching route") + } + + if foobarMatcher.Handler != foobarHandler { + t.Fatalf("Error matching priority") + } + + if foobarMatcher.Handler == fooHandler { + t.Fatalf("Error matching priority") + } +} + +type fakeHandler struct { + name string +} + +func (h *fakeHandler) ServeHTTP(http.ResponseWriter, *http.Request) { + +} + From f4cb4bb1b8ebf20fdd4ed94c3a56c91952b3a78f Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Mon, 6 Jun 2016 22:30:23 +0200 Subject: [PATCH 6/8] Add routes priorities in providers Signed-off-by: Emile Vauge --- provider/docker.go | 8 ++++++++ provider/marathon.go | 8 ++++++++ templates/consul_catalog.tmpl | 1 + templates/docker.tmpl | 1 + templates/kv.tmpl | 1 + templates/marathon.tmpl | 1 + types/types.go | 4 ++-- .../providers/frontend-monitor/frontend-monitor.html | 5 +++-- 8 files changed, 25 insertions(+), 4 deletions(-) diff --git a/provider/docker.go b/provider/docker.go index 657eabfda..30e651305 100644 --- a/provider/docker.go +++ b/provider/docker.go @@ -167,6 +167,7 @@ func (provider *Docker) loadDockerConfig(containersInspected []dockertypes.Conta "getDomain": provider.getDomain, "getProtocol": provider.getProtocol, "getPassHostHeader": provider.getPassHostHeader, + "getPriority": provider.getPriority, "getEntryPoints": provider.getEntryPoints, "getFrontendRule": provider.getFrontendRule, "replace": replace, @@ -300,6 +301,13 @@ func (provider *Docker) getPassHostHeader(container dockertypes.ContainerJSON) s return "true" } +func (provider *Docker) getPriority(container dockertypes.ContainerJSON) string { + if priority, err := getLabel(container, "traefik.frontend.priority"); err == nil { + return priority + } + return "0" +} + func (provider *Docker) getEntryPoints(container dockertypes.ContainerJSON) []string { if entryPoints, err := getLabel(container, "traefik.frontend.entryPoints"); err == nil { return strings.Split(entryPoints, ",") diff --git a/provider/marathon.go b/provider/marathon.go index a97e70ecb..4efdc390a 100644 --- a/provider/marathon.go +++ b/provider/marathon.go @@ -116,6 +116,7 @@ func (provider *Marathon) loadMarathonConfig() *types.Configuration { "getDomain": provider.getDomain, "getProtocol": provider.getProtocol, "getPassHostHeader": provider.getPassHostHeader, + "getPriority": provider.getPriority, "getEntryPoints": provider.getEntryPoints, "getFrontendRule": provider.getFrontendRule, "getFrontendBackend": provider.getFrontendBackend, @@ -322,6 +323,13 @@ func (provider *Marathon) getPassHostHeader(application marathon.Application) st return "true" } +func (provider *Marathon) getPriority(application marathon.Application) string { + if priority, err := provider.getLabel(application, "traefik.frontend.priority"); err == nil { + return priority + } + return "0" +} + func (provider *Marathon) getEntryPoints(application marathon.Application) []string { if entryPoints, err := provider.getLabel(application, "traefik.frontend.entryPoints"); err == nil { return strings.Split(entryPoints, ",") diff --git a/templates/consul_catalog.tmpl b/templates/consul_catalog.tmpl index 7724fd2b9..20d0a8f19 100644 --- a/templates/consul_catalog.tmpl +++ b/templates/consul_catalog.tmpl @@ -30,6 +30,7 @@ [frontends.frontend-{{.ServiceName}}] backend = "backend-{{.ServiceName}}" passHostHeader = {{getAttribute "frontend.passHostHeader" .Attributes "true"}} + priority = {{getAttribute "frontend.priority" .Attributes "0"}} {{$entryPoints := getAttribute "frontend.entrypoints" .Attributes ""}} {{with $entryPoints}} entrypoints = [{{range getEntryPoints $entryPoints}} diff --git a/templates/docker.tmpl b/templates/docker.tmpl index 08e1f54b5..a45963d5f 100644 --- a/templates/docker.tmpl +++ b/templates/docker.tmpl @@ -8,6 +8,7 @@ [frontends."frontend-{{$frontend}}"]{{$container := index $containers 0}} backend = "backend-{{getBackend $container}}" passHostHeader = {{getPassHostHeader $container}} + priority = {{getPriority $container}} entryPoints = [{{range getEntryPoints $container}} "{{.}}", {{end}}] diff --git a/templates/kv.tmpl b/templates/kv.tmpl index 32c227af9..f27235010 100644 --- a/templates/kv.tmpl +++ b/templates/kv.tmpl @@ -40,6 +40,7 @@ [frontends."{{$frontend}}"] backend = "{{Get "" . "/backend"}}" passHostHeader = {{Get "true" . "/passHostHeader"}} + priority = {{Get "0" . "/priority"}} entryPoints = [{{range $entryPoints}} "{{.}}", {{end}}] diff --git a/templates/marathon.tmpl b/templates/marathon.tmpl index d2243cf47..26194fab7 100644 --- a/templates/marathon.tmpl +++ b/templates/marathon.tmpl @@ -9,6 +9,7 @@ [frontends.frontend{{.ID | replace "/" "-"}}] backend = "backend{{getFrontendBackend .}}" passHostHeader = {{getPassHostHeader .}} + priority = {{getPriority .}} entryPoints = [{{range getEntryPoints .}} "{{.}}", {{end}}] diff --git a/types/types.go b/types/types.go index 7d521ed23..322ce47d6 100644 --- a/types/types.go +++ b/types/types.go @@ -34,7 +34,7 @@ type CircuitBreaker struct { // Server holds server configuration. type Server struct { URL string `json:"url,omitempty"` - Weight int `json:"weight,omitempty"` + Weight int `json:"weight"` } // Route holds route configuration. @@ -52,7 +52,7 @@ type Frontend struct { Backend string `json:"backend,omitempty"` Routes map[string]Route `json:"routes,omitempty"` PassHostHeader bool `json:"passHostHeader,omitempty"` - Priority int `json:"priority,omitempty"` + Priority int `json:"priority"` } // LoadBalancerMethod holds the method of load balancing to use. diff --git a/webui/src/app/sections/providers/frontend-monitor/frontend-monitor.html b/webui/src/app/sections/providers/frontend-monitor/frontend-monitor.html index 6881c4bd8..eb5f8187f 100644 --- a/webui/src/app/sections/providers/frontend-monitor/frontend-monitor.html +++ b/webui/src/app/sections/providers/frontend-monitor/frontend-monitor.html @@ -16,7 +16,8 @@ From cc4fb64b34f87c8235abc5ed3d27c82aca681ae1 Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Mon, 6 Jun 2016 22:33:29 +0200 Subject: [PATCH 7/8] Add routes priorities in integration tests Signed-off-by: Emile Vauge --- examples/compose-marathon.yml | 9 --------- examples/whoami.json | 3 ++- integration/consul_test.go | 2 ++ integration/etcd_test.go | 5 +++-- integration/marathon_test.go | 13 +++++++++++++ integration/resources/compose/marathon.yml | 9 +++++---- 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/examples/compose-marathon.yml b/examples/compose-marathon.yml index 7239cba8f..76233f396 100644 --- a/examples/compose-marathon.yml +++ b/examples/compose-marathon.yml @@ -41,12 +41,3 @@ marathon: MARATHON_ZK: zk://127.0.0.1:2181/marathon MARATHON_HOSTNAME: 127.0.0.1 command: --event_subscriber http_callback - -traefik: - image: containous/traefik - command: -c /dev/null --web --logLevel=DEBUG --marathon --marathon.domain marathon.localhost --marathon.endpoint http://172.17.0.1:8080 --marathon.watch - ports: - - "8000:80" - - "8081:8080" - volumes: - - /var/run/docker.sock:/var/run/docker.sock \ No newline at end of file diff --git a/examples/whoami.json b/examples/whoami.json index 980316388..5b3ab3da2 100644 --- a/examples/whoami.json +++ b/examples/whoami.json @@ -26,6 +26,7 @@ "labels": { "traefik.weight": "1", "traefik.protocol": "http", - "traefik.frontend.rule" : "Host:test.marathon.localhost" + "traefik.frontend.rule" : "Host:test.marathon.localhost", + "traefik.frontend.priority" : "10" } } diff --git a/integration/consul_test.go b/integration/consul_test.go index b87105de0..0c2c97058 100644 --- a/integration/consul_test.go +++ b/integration/consul_test.go @@ -100,11 +100,13 @@ func (s *ConsulSuite) TestNominalConfiguration(c *check.C) { frontend1 := map[string]string{ "traefik/frontends/frontend1/backend": "backend2", "traefik/frontends/frontend1/entrypoints": "http", + "traefik/frontends/frontend1/priority": "1", "traefik/frontends/frontend1/routes/test_1/rule": "Host:test.localhost", } frontend2 := map[string]string{ "traefik/frontends/frontend2/backend": "backend1", "traefik/frontends/frontend2/entrypoints": "http", + "traefik/frontends/frontend2/priority": "10", "traefik/frontends/frontend2/routes/test_2/rule": "Path:/test", } for key, value := range backend1 { diff --git a/integration/etcd_test.go b/integration/etcd_test.go index 1138eea3d..316d989b3 100644 --- a/integration/etcd_test.go +++ b/integration/etcd_test.go @@ -1,12 +1,11 @@ package main import ( + "github.com/go-check/check" "net/http" "os/exec" "time" - "github.com/go-check/check" - checker "github.com/vdemeester/shakers" "errors" @@ -104,11 +103,13 @@ func (s *EtcdSuite) TestNominalConfiguration(c *check.C) { frontend1 := map[string]string{ "/traefik/frontends/frontend1/backend": "backend2", "/traefik/frontends/frontend1/entrypoints": "http", + "/traefik/frontends/frontend1/priority": "1", "/traefik/frontends/frontend1/routes/test_1/rule": "Host:test.localhost", } frontend2 := map[string]string{ "/traefik/frontends/frontend2/backend": "backend1", "/traefik/frontends/frontend2/entrypoints": "http", + "/traefik/frontends/frontend2/priority": "10", "/traefik/frontends/frontend2/routes/test_2/rule": "Path:/test", } for key, value := range backend1 { diff --git a/integration/marathon_test.go b/integration/marathon_test.go index 0453cbea2..e029794f6 100644 --- a/integration/marathon_test.go +++ b/integration/marathon_test.go @@ -15,6 +15,19 @@ type MarathonSuite struct{ BaseSuite } func (s *MarathonSuite) SetUpSuite(c *check.C) { s.createComposeProject(c, "marathon") + s.composeProject.Start(c) + // wait for marathon + // err := utils.TryRequest("http://127.0.0.1:8080/ping", 60*time.Second, func(res *http.Response) error { + // body, err := ioutil.ReadAll(res.Body) + // if err != nil { + // return err + // } + // if !strings.Contains(string(body), "ping") { + // return errors.New("Incorrect marathon config") + // } + // return nil + // }) + // c.Assert(err, checker.IsNil) } func (s *MarathonSuite) TestSimpleConfiguration(c *check.C) { diff --git a/integration/resources/compose/marathon.yml b/integration/resources/compose/marathon.yml index d489db2fa..13113e51e 100644 --- a/integration/resources/compose/marathon.yml +++ b/integration/resources/compose/marathon.yml @@ -6,7 +6,7 @@ zk: ZK_ID: " 1" master: - image: mesosphere/mesos-master:0.23.0-1.0.ubuntu1404 + image: mesosphere/mesos-master:0.28.1-2.0.20.ubuntu1404 net: host environment: MESOS_ZK: zk://127.0.0.1:2181/mesos @@ -17,7 +17,7 @@ master: MESOS_WORK_DIR: /var/lib/mesos slave: - image: mesosphere/mesos-slave:0.23.0-1.0.ubuntu1404 + image: mesosphere/mesos-slave:0.28.1-2.0.20.ubuntu1404 net: host pid: host privileged: true @@ -31,12 +31,13 @@ slave: - /usr/bin/docker:/usr/bin/docker:ro - /usr/lib/x86_64-linux-gnu/libapparmor.so.1:/usr/lib/x86_64-linux-gnu/libapparmor.so.1:ro - /var/run/docker.sock:/var/run/docker.sock + - /lib/x86_64-linux-gnu/libsystemd-journal.so.0:/lib/x86_64-linux-gnu/libsystemd-journal.so.0 marathon: - image: mesosphere/marathon:v0.9.2 + image: mesosphere/marathon:v1.1.1 net: host environment: MARATHON_MASTER: zk://127.0.0.1:2181/mesos MARATHON_ZK: zk://127.0.0.1:2181/marathon MARATHON_HOSTNAME: 127.0.0.1 - command: --event_subscriber http_callback + command: --event_subscriber http_callback \ No newline at end of file From 7e6c580130615387d9bcb7a7f5a25bdec3ff5c4a Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Mon, 6 Jun 2016 22:40:42 +0200 Subject: [PATCH 8/8] Add routes priorities in documentation Signed-off-by: Emile Vauge --- docs/basics.md | 22 ++++++++++++++++++++++ docs/toml.md | 32 +++++++++++++++++++------------- rules_test.go | 3 +-- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/docs/basics.md b/docs/basics.md index 2b6331824..b09751b7a 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -84,6 +84,7 @@ Here is an example of frontends definition: [frontends.frontend2] backend = "backend1" passHostHeader = true + priority = 10 entrypoints = ["https"] # overrides defaultEntryPoints [frontends.frontend2.routes.test_1] rule = "Host: localhost, {subdomain:[a-z]+}.localhost" @@ -97,6 +98,27 @@ Here is an example of frontends definition: - `frontend2` will forward the traffic to the `backend1` if the rule `Host: localhost, {subdomain:[a-z]+}.localhost` is matched (forwarding client `Host` header to the backend) - `frontend3` will forward the traffic to the `backend2` if the rules `Host: test3.localhost` and `Path:/test` are matched +By default, routes will be sorted using rules length (to avoid path overlap): +`PathPrefix:/12345` will be matched before `PathPrefix:/1234` that will be matched before `PathPrefix:/1`. + +You can customize priority by frontend: + +``` + [frontends] + [frontends.frontend1] + backend = "backend1" + priority = 10 + passHostHeader = true + [frontends.frontend1.routes.test_1] + rule = "PathPrefix:/to" + [frontends.frontend2] + priority = 5 + backend = "backend2" + passHostHeader = true + [frontends.frontend2.routes.test_1] + rule = "PathPrefix:/toto" +``` + ## Backends A backend is responsible to load-balance the traffic coming from one or more frontends to a set of http servers. diff --git a/docs/toml.md b/docs/toml.md index 254280691..366cf91a8 100644 --- a/docs/toml.md +++ b/docs/toml.md @@ -301,6 +301,7 @@ defaultEntryPoints = ["http", "https"] [frontends.frontend2] backend = "backend1" passHostHeader = true + priority = 10 entrypoints = ["https"] # overrides defaultEntryPoints [frontends.frontend2.routes.test_1] rule = "Host:{subdomain:[a-z]+}.localhost" @@ -367,6 +368,7 @@ filename = "rules.toml" [frontends.frontend2] backend = "backend1" passHostHeader = true + priority = 10 entrypoints = ["https"] # overrides defaultEntryPoints [frontends.frontend2.routes.test_1] rule = "Host:{subdomain:[a-z]+}.localhost" @@ -583,6 +585,7 @@ Labels can be used on containers to override default behaviour: - `traefik.enable=false`: disable this container in Træfɪk - `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`). - `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend. +- `traefik.frontend.priority=10`: override default frontend priority - `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. - `traefik.domain=traefik.localhost`: override the default domain - `traefik.docker.network`: Set the docker network to use for connections to this container @@ -673,6 +676,7 @@ Labels can be used on containers to override default behaviour: - `traefik.enable=false`: disable this application in Træfɪk - `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`). - `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend. +- `traefik.frontend.priority=10`: override default frontend priority - `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. - `traefik.domain=traefik.localhost`: override the default domain @@ -810,14 +814,15 @@ used in consul. Additional settings can be defined using Consul Catalog tags: -- ```traefik.enable=false```: disable this container in Træfɪk -- ```traefik.protocol=https```: override the default `http` protocol -- ```traefik.backend.weight=10```: assign this weight to the container -- ```traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5``` -- ```traefik.backend.loadbalancer=drr```: override the default load balancing mode -- ```traefik.frontend.rule=Host:test.traefik.io```: override the default frontend rule (Default: `Host:{containerName}.{domain}`). -- ```traefik.frontend.passHostHeader=true```: forward client `Host` header to the backend. -- ```traefik.frontend.entryPoints=http,https```: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. +- `traefik.enable=false`: disable this container in Træfɪk +- `traefik.protocol=https`: override the default `http` protocol +- `traefik.backend.weight=10`: assign this weight to the container +- `traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5` +- `traefik.backend.loadbalancer=drr`: override the default load balancing mode +- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`). +- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend. +- `traefik.frontend.priority=10`: override default frontend priority +- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. ## Etcd backend @@ -991,11 +996,12 @@ The Keys-Values structure should look (using `prefix = "/traefik"`): - frontend 2 -| Key | Value | -|----------------------------------------------------|--------------| -| `/traefik/frontends/frontend2/backend` | `backend1` | -| `/traefik/frontends/frontend2/passHostHeader` | `true` | -| `/traefik/frontends/frontend2/entrypoints` | `http,https` | +| Key | Value | +|----------------------------------------------------|--------------------| +| `/traefik/frontends/frontend2/backend` | `backend1` | +| `/traefik/frontends/frontend2/passHostHeader` | `true` | +| `/traefik/frontends/frontend2/priority` | `10` | +| `/traefik/frontends/frontend2/entrypoints` | `http,https` | | `/traefik/frontends/frontend2/routes/test_2/rule` | `PathPrefix:/test` | ## Atomic configuration changes diff --git a/rules_test.go b/rules_test.go index bac10e07d..96c41b475 100644 --- a/rules_test.go +++ b/rules_test.go @@ -3,6 +3,7 @@ package main import ( "github.com/containous/mux" "net/http" + "net/url" "testing" ) @@ -52,7 +53,6 @@ func TestParseTwoRules(t *testing.T) { } } - func TestPriorites(t *testing.T) { router := mux.NewRouter() router.StrictSlash(true) @@ -130,4 +130,3 @@ type fakeHandler struct { func (h *fakeHandler) ServeHTTP(http.ResponseWriter, *http.Request) { } -