Merge branch 'master' into master
This commit is contained in:
commit
1274d26b4c
25 changed files with 294 additions and 79 deletions
|
@ -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:
|
||||
|
@ -82,18 +84,40 @@ 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"
|
||||
[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
|
||||
|
||||
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
|
||||
|
||||
|
|
32
docs/toml.md
32
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
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
16
glide.lock
generated
16
glide.lock
generated
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
|
@ -1,8 +1,8 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/containous/mux"
|
||||
"github.com/containous/traefik/safe"
|
||||
"github.com/gorilla/mux"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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, ",")
|
||||
|
|
|
@ -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, ",")
|
||||
|
|
76
rules.go
76
rules.go
|
@ -2,7 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/containous/mux"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
@ -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
|
||||
}
|
||||
|
|
132
rules_test.go
Normal file
132
rules_test.go
Normal file
|
@ -0,0 +1,132 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/containous/mux"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"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")
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
}
|
10
server.go
10
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
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}]
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
[frontends."{{$frontend}}"]
|
||||
backend = "{{Get "" . "/backend"}}"
|
||||
passHostHeader = {{Get "true" . "/passHostHeader"}}
|
||||
priority = {{Get "0" . "/priority"}}
|
||||
entryPoints = [{{range $entryPoints}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
[frontends.frontend{{.ID | replace "/" "-"}}]
|
||||
backend = "backend{{getFrontendBackend .}}"
|
||||
passHostHeader = {{getPassHostHeader .}}
|
||||
priority = {{getPriority .}}
|
||||
entryPoints = [{{range getEntryPoints .}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,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"`
|
||||
}
|
||||
|
||||
// LoadBalancerMethod holds the method of load balancing to use.
|
||||
|
|
2
web.go
2
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"
|
||||
)
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
</div>
|
||||
<div data-bg-show="frontendCtrl.frontend.backend" class="panel-footer">
|
||||
<span data-ng-repeat="entryPoint in frontendCtrl.frontend.entryPoints"><span class="label label-primary">{{entryPoint}}</span><span data-ng-hide="$last"> </span></span>
|
||||
<span class="label label-warning" role="button" data-toggle="collapse" href="#{{frontendCtrl.frontend.backend}}" aria-expanded="false">{{frontendCtrl.frontend.backend}}</span>
|
||||
<span data-ng-show="frontendCtrl.frontend.passHostHeader" class="label label-warning">Pass Host Header</span>
|
||||
<span class="label label-warning" role="button" data-toggle="collapse" href="#{{frontendCtrl.frontend.backend}}" aria-expanded="false">Backend:{{frontendCtrl.frontend.backend}}</span>
|
||||
<span data-ng-show="frontendCtrl.frontend.passHostHeader" class="label label-warning">PassHostHeader</span>
|
||||
<span data-ng-show="frontendCtrl.frontend.priority" class="label label-warning">Priority:{{frontendCtrl.frontend.priority}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue