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.
|
- `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.
|
- `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.
|
You can optionally enable `passHostHeader` to forward client `Host` header to the backend.
|
||||||
|
|
||||||
Here is an example of frontends definition:
|
Here is an example of frontends definition:
|
||||||
|
@ -82,18 +84,40 @@ Here is an example of frontends definition:
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
|
priority = 10
|
||||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
[frontends.frontend2.routes.test_1]
|
[frontends.frontend2.routes.test_1]
|
||||||
rule = "Host: localhost, {subdomain:[a-z]+}.localhost"
|
rule = "Host: localhost, {subdomain:[a-z]+}.localhost"
|
||||||
[frontends.frontend3]
|
[frontends.frontend3]
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
rule = "Path:/test"
|
rule = "Host: test3.localhost;Path:/test"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Three frontends are defined: `frontend1`, `frontend2` and `frontend3`
|
- 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
|
- `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)
|
- `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
|
## Backends
|
||||||
|
|
||||||
|
|
24
docs/toml.md
24
docs/toml.md
|
@ -301,6 +301,7 @@ defaultEntryPoints = ["http", "https"]
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
|
priority = 10
|
||||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
[frontends.frontend2.routes.test_1]
|
[frontends.frontend2.routes.test_1]
|
||||||
rule = "Host:{subdomain:[a-z]+}.localhost"
|
rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||||
|
@ -367,6 +368,7 @@ filename = "rules.toml"
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
|
priority = 10
|
||||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
[frontends.frontend2.routes.test_1]
|
[frontends.frontend2.routes.test_1]
|
||||||
rule = "Host:{subdomain:[a-z]+}.localhost"
|
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.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.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.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.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||||
- `traefik.domain=traefik.localhost`: override the default domain
|
- `traefik.domain=traefik.localhost`: override the default domain
|
||||||
- `traefik.docker.network`: Set the docker network to use for connections to this container
|
- `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.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.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.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.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||||
- `traefik.domain=traefik.localhost`: override the default domain
|
- `traefik.domain=traefik.localhost`: override the default domain
|
||||||
|
|
||||||
|
@ -810,14 +814,15 @@ used in consul.
|
||||||
|
|
||||||
Additional settings can be defined using Consul Catalog tags:
|
Additional settings can be defined using Consul Catalog tags:
|
||||||
|
|
||||||
- ```traefik.enable=false```: disable this container in Træfɪk
|
- `traefik.enable=false`: disable this container in Træfɪk
|
||||||
- ```traefik.protocol=https```: override the default `http` protocol
|
- `traefik.protocol=https`: override the default `http` protocol
|
||||||
- ```traefik.backend.weight=10```: assign this weight to the container
|
- `traefik.backend.weight=10`: assign this weight to the container
|
||||||
- ```traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5```
|
- `traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5`
|
||||||
- ```traefik.backend.loadbalancer=drr```: override the default load balancing mode
|
- `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.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.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.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
|
## Etcd backend
|
||||||
|
|
||||||
|
@ -992,9 +997,10 @@ The Keys-Values structure should look (using `prefix = "/traefik"`):
|
||||||
- frontend 2
|
- frontend 2
|
||||||
|
|
||||||
| Key | Value |
|
| Key | Value |
|
||||||
|----------------------------------------------------|--------------|
|
|----------------------------------------------------|--------------------|
|
||||||
| `/traefik/frontends/frontend2/backend` | `backend1` |
|
| `/traefik/frontends/frontend2/backend` | `backend1` |
|
||||||
| `/traefik/frontends/frontend2/passHostHeader` | `true` |
|
| `/traefik/frontends/frontend2/passHostHeader` | `true` |
|
||||||
|
| `/traefik/frontends/frontend2/priority` | `10` |
|
||||||
| `/traefik/frontends/frontend2/entrypoints` | `http,https` |
|
| `/traefik/frontends/frontend2/entrypoints` | `http,https` |
|
||||||
| `/traefik/frontends/frontend2/routes/test_2/rule` | `PathPrefix:/test` |
|
| `/traefik/frontends/frontend2/routes/test_2/rule` | `PathPrefix:/test` |
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,3 @@ marathon:
|
||||||
MARATHON_ZK: zk://127.0.0.1:2181/marathon
|
MARATHON_ZK: zk://127.0.0.1:2181/marathon
|
||||||
MARATHON_HOSTNAME: 127.0.0.1
|
MARATHON_HOSTNAME: 127.0.0.1
|
||||||
command: --event_subscriber http_callback
|
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": {
|
"labels": {
|
||||||
"traefik.weight": "1",
|
"traefik.weight": "1",
|
||||||
"traefik.protocol": "http",
|
"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
|
hash: 5a6dbc30a69abd002736bd5113e0f783c448faee20a0791c724ec2c3c1cfb8bb
|
||||||
updated: 2016-06-02T15:11:52.77657652+02:00
|
updated: 2016-06-03T18:11:43.839017153+02:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/boltdb/bolt
|
- name: github.com/boltdb/bolt
|
||||||
version: dfb21201d9270c1082d5fb0f07f500311ff72f18
|
version: dfb21201d9270c1082d5fb0f07f500311ff72f18
|
||||||
|
@ -16,9 +16,11 @@ imports:
|
||||||
- name: github.com/codegangsta/cli
|
- name: github.com/codegangsta/cli
|
||||||
version: bf4a526f48af7badd25d2cb02d587e1b01be3b50
|
version: bf4a526f48af7badd25d2cb02d587e1b01be3b50
|
||||||
- name: github.com/codegangsta/negroni
|
- name: github.com/codegangsta/negroni
|
||||||
version: fb7b7c045dfb05dc81a5c3688c568550b5bd6e36
|
version: feacfc52d357c844f524c794947493483ed881b3
|
||||||
- name: github.com/containous/flaeg
|
- name: github.com/containous/flaeg
|
||||||
version: b98687da5c323650f4513fda6b6203fcbdec9313
|
version: b98687da5c323650f4513fda6b6203fcbdec9313
|
||||||
|
- name: github.com/containous/mux
|
||||||
|
version: a819b77bba13f0c0cbe36e437bc2e948411b3996
|
||||||
- name: github.com/containous/oxy
|
- name: github.com/containous/oxy
|
||||||
version: 183212964e13e7b8afe01a08b193d04300554a68
|
version: 183212964e13e7b8afe01a08b193d04300554a68
|
||||||
subpackages:
|
subpackages:
|
||||||
|
@ -43,7 +45,7 @@ imports:
|
||||||
subpackages:
|
subpackages:
|
||||||
- spew
|
- spew
|
||||||
- name: github.com/docker/distribution
|
- name: github.com/docker/distribution
|
||||||
version: bb330cd684eb4afab9cc4f2453d7c8918099d7ee
|
version: feddf6cd4e439577ab270d8e3ba63a5d7c5c0d55
|
||||||
subpackages:
|
subpackages:
|
||||||
- reference
|
- reference
|
||||||
- digest
|
- digest
|
||||||
|
@ -100,10 +102,8 @@ imports:
|
||||||
- query
|
- query
|
||||||
- name: github.com/gorilla/context
|
- name: github.com/gorilla/context
|
||||||
version: aed02d124ae4a0e94fea4541c8effd05bf0c8296
|
version: aed02d124ae4a0e94fea4541c8effd05bf0c8296
|
||||||
- name: github.com/gorilla/mux
|
|
||||||
version: bd09be08ed4377796d312df0a45314e11b8f5dc1
|
|
||||||
- name: github.com/hashicorp/consul
|
- name: github.com/hashicorp/consul
|
||||||
version: ebf7ea1d759184c02a5bb5263a7c52d29838ffc3
|
version: 802b29ab948dedb7f7b1b903f535bdf250388c50
|
||||||
subpackages:
|
subpackages:
|
||||||
- api
|
- api
|
||||||
- name: github.com/hashicorp/go-cleanhttp
|
- name: github.com/hashicorp/go-cleanhttp
|
||||||
|
@ -136,7 +136,7 @@ imports:
|
||||||
- name: github.com/ogier/pflag
|
- name: github.com/ogier/pflag
|
||||||
version: 45c278ab3607870051a2ea9040bb85fcb8557481
|
version: 45c278ab3607870051a2ea9040bb85fcb8557481
|
||||||
- name: github.com/opencontainers/runc
|
- name: github.com/opencontainers/runc
|
||||||
version: 6c485e6902bb9dd77b8234042b8f00e20ef87a18
|
version: 3211c9f721237f55a16da9c111e3d7e8777e53b5
|
||||||
subpackages:
|
subpackages:
|
||||||
- libcontainer/user
|
- libcontainer/user
|
||||||
- name: github.com/parnurzeal/gorequest
|
- name: github.com/parnurzeal/gorequest
|
||||||
|
|
|
@ -40,7 +40,7 @@ import:
|
||||||
- package: github.com/elazarl/go-bindata-assetfs
|
- package: github.com/elazarl/go-bindata-assetfs
|
||||||
- package: github.com/gambol99/go-marathon
|
- package: github.com/gambol99/go-marathon
|
||||||
version: ade11d1dc2884ee1f387078fc28509559b6235d1
|
version: ade11d1dc2884ee1f387078fc28509559b6235d1
|
||||||
- package: github.com/gorilla/mux
|
- package: github.com/containous/mux
|
||||||
- package: github.com/hashicorp/consul
|
- package: github.com/hashicorp/consul
|
||||||
subpackages:
|
subpackages:
|
||||||
- api
|
- api
|
||||||
|
|
|
@ -100,11 +100,13 @@ func (s *ConsulSuite) TestNominalConfiguration(c *check.C) {
|
||||||
frontend1 := map[string]string{
|
frontend1 := map[string]string{
|
||||||
"traefik/frontends/frontend1/backend": "backend2",
|
"traefik/frontends/frontend1/backend": "backend2",
|
||||||
"traefik/frontends/frontend1/entrypoints": "http",
|
"traefik/frontends/frontend1/entrypoints": "http",
|
||||||
|
"traefik/frontends/frontend1/priority": "1",
|
||||||
"traefik/frontends/frontend1/routes/test_1/rule": "Host:test.localhost",
|
"traefik/frontends/frontend1/routes/test_1/rule": "Host:test.localhost",
|
||||||
}
|
}
|
||||||
frontend2 := map[string]string{
|
frontend2 := map[string]string{
|
||||||
"traefik/frontends/frontend2/backend": "backend1",
|
"traefik/frontends/frontend2/backend": "backend1",
|
||||||
"traefik/frontends/frontend2/entrypoints": "http",
|
"traefik/frontends/frontend2/entrypoints": "http",
|
||||||
|
"traefik/frontends/frontend2/priority": "10",
|
||||||
"traefik/frontends/frontend2/routes/test_2/rule": "Path:/test",
|
"traefik/frontends/frontend2/routes/test_2/rule": "Path:/test",
|
||||||
}
|
}
|
||||||
for key, value := range backend1 {
|
for key, value := range backend1 {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/go-check/check"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-check/check"
|
|
||||||
|
|
||||||
checker "github.com/vdemeester/shakers"
|
checker "github.com/vdemeester/shakers"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -104,11 +103,13 @@ func (s *EtcdSuite) TestNominalConfiguration(c *check.C) {
|
||||||
frontend1 := map[string]string{
|
frontend1 := map[string]string{
|
||||||
"/traefik/frontends/frontend1/backend": "backend2",
|
"/traefik/frontends/frontend1/backend": "backend2",
|
||||||
"/traefik/frontends/frontend1/entrypoints": "http",
|
"/traefik/frontends/frontend1/entrypoints": "http",
|
||||||
|
"/traefik/frontends/frontend1/priority": "1",
|
||||||
"/traefik/frontends/frontend1/routes/test_1/rule": "Host:test.localhost",
|
"/traefik/frontends/frontend1/routes/test_1/rule": "Host:test.localhost",
|
||||||
}
|
}
|
||||||
frontend2 := map[string]string{
|
frontend2 := map[string]string{
|
||||||
"/traefik/frontends/frontend2/backend": "backend1",
|
"/traefik/frontends/frontend2/backend": "backend1",
|
||||||
"/traefik/frontends/frontend2/entrypoints": "http",
|
"/traefik/frontends/frontend2/entrypoints": "http",
|
||||||
|
"/traefik/frontends/frontend2/priority": "10",
|
||||||
"/traefik/frontends/frontend2/routes/test_2/rule": "Path:/test",
|
"/traefik/frontends/frontend2/routes/test_2/rule": "Path:/test",
|
||||||
}
|
}
|
||||||
for key, value := range backend1 {
|
for key, value := range backend1 {
|
||||||
|
|
|
@ -15,6 +15,19 @@ type MarathonSuite struct{ BaseSuite }
|
||||||
|
|
||||||
func (s *MarathonSuite) SetUpSuite(c *check.C) {
|
func (s *MarathonSuite) SetUpSuite(c *check.C) {
|
||||||
s.createComposeProject(c, "marathon")
|
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) {
|
func (s *MarathonSuite) TestSimpleConfiguration(c *check.C) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ zk:
|
||||||
ZK_ID: " 1"
|
ZK_ID: " 1"
|
||||||
|
|
||||||
master:
|
master:
|
||||||
image: mesosphere/mesos-master:0.23.0-1.0.ubuntu1404
|
image: mesosphere/mesos-master:0.28.1-2.0.20.ubuntu1404
|
||||||
net: host
|
net: host
|
||||||
environment:
|
environment:
|
||||||
MESOS_ZK: zk://127.0.0.1:2181/mesos
|
MESOS_ZK: zk://127.0.0.1:2181/mesos
|
||||||
|
@ -17,7 +17,7 @@ master:
|
||||||
MESOS_WORK_DIR: /var/lib/mesos
|
MESOS_WORK_DIR: /var/lib/mesos
|
||||||
|
|
||||||
slave:
|
slave:
|
||||||
image: mesosphere/mesos-slave:0.23.0-1.0.ubuntu1404
|
image: mesosphere/mesos-slave:0.28.1-2.0.20.ubuntu1404
|
||||||
net: host
|
net: host
|
||||||
pid: host
|
pid: host
|
||||||
privileged: true
|
privileged: true
|
||||||
|
@ -31,9 +31,10 @@ slave:
|
||||||
- /usr/bin/docker:/usr/bin/docker:ro
|
- /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
|
- /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
|
- /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:
|
marathon:
|
||||||
image: mesosphere/marathon:v0.9.2
|
image: mesosphere/marathon:v1.1.1
|
||||||
net: host
|
net: host
|
||||||
environment:
|
environment:
|
||||||
MARATHON_MASTER: zk://127.0.0.1:2181/mesos
|
MARATHON_MASTER: zk://127.0.0.1:2181/mesos
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package middlewares
|
package middlewares
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/containous/mux"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/containous/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Routes holds the gorilla mux routes (for the API & co).
|
// Routes holds the gorilla mux routes (for the API & co).
|
||||||
|
|
|
@ -167,6 +167,7 @@ func (provider *Docker) loadDockerConfig(containersInspected []dockertypes.Conta
|
||||||
"getDomain": provider.getDomain,
|
"getDomain": provider.getDomain,
|
||||||
"getProtocol": provider.getProtocol,
|
"getProtocol": provider.getProtocol,
|
||||||
"getPassHostHeader": provider.getPassHostHeader,
|
"getPassHostHeader": provider.getPassHostHeader,
|
||||||
|
"getPriority": provider.getPriority,
|
||||||
"getEntryPoints": provider.getEntryPoints,
|
"getEntryPoints": provider.getEntryPoints,
|
||||||
"getFrontendRule": provider.getFrontendRule,
|
"getFrontendRule": provider.getFrontendRule,
|
||||||
"replace": replace,
|
"replace": replace,
|
||||||
|
@ -300,6 +301,13 @@ func (provider *Docker) getPassHostHeader(container dockertypes.ContainerJSON) s
|
||||||
return "true"
|
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 {
|
func (provider *Docker) getEntryPoints(container dockertypes.ContainerJSON) []string {
|
||||||
if entryPoints, err := getLabel(container, "traefik.frontend.entryPoints"); err == nil {
|
if entryPoints, err := getLabel(container, "traefik.frontend.entryPoints"); err == nil {
|
||||||
return strings.Split(entryPoints, ",")
|
return strings.Split(entryPoints, ",")
|
||||||
|
|
|
@ -116,6 +116,7 @@ func (provider *Marathon) loadMarathonConfig() *types.Configuration {
|
||||||
"getDomain": provider.getDomain,
|
"getDomain": provider.getDomain,
|
||||||
"getProtocol": provider.getProtocol,
|
"getProtocol": provider.getProtocol,
|
||||||
"getPassHostHeader": provider.getPassHostHeader,
|
"getPassHostHeader": provider.getPassHostHeader,
|
||||||
|
"getPriority": provider.getPriority,
|
||||||
"getEntryPoints": provider.getEntryPoints,
|
"getEntryPoints": provider.getEntryPoints,
|
||||||
"getFrontendRule": provider.getFrontendRule,
|
"getFrontendRule": provider.getFrontendRule,
|
||||||
"getFrontendBackend": provider.getFrontendBackend,
|
"getFrontendBackend": provider.getFrontendBackend,
|
||||||
|
@ -322,6 +323,13 @@ func (provider *Marathon) getPassHostHeader(application marathon.Application) st
|
||||||
return "true"
|
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 {
|
func (provider *Marathon) getEntryPoints(application marathon.Application) []string {
|
||||||
if entryPoints, err := provider.getLabel(application, "traefik.frontend.entryPoints"); err == nil {
|
if entryPoints, err := provider.getLabel(application, "traefik.frontend.entryPoints"); err == nil {
|
||||||
return strings.Split(entryPoints, ",")
|
return strings.Split(entryPoints, ",")
|
||||||
|
|
32
rules.go
32
rules.go
|
@ -2,7 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/gorilla/mux"
|
"github.com/containous/mux"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -109,23 +109,34 @@ func (r *Rules) Parse(expression string) (*mux.Route, error) {
|
||||||
f := func(c rune) bool {
|
f := func(c rune) bool {
|
||||||
return c == ':'
|
return c == ':'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow multiple rules separated by ;
|
||||||
|
splitRule := func(c rune) bool {
|
||||||
|
return c == ';'
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedRules := strings.FieldsFunc(expression, splitRule)
|
||||||
|
|
||||||
|
var resultRoute *mux.Route
|
||||||
|
|
||||||
|
for _, rule := range parsedRules {
|
||||||
// get function
|
// get function
|
||||||
parsedFunctions := strings.FieldsFunc(expression, f)
|
parsedFunctions := strings.FieldsFunc(rule, f)
|
||||||
if len(parsedFunctions) == 0 {
|
if len(parsedFunctions) == 0 {
|
||||||
return nil, errors.New("Error parsing rule: " + expression)
|
return nil, errors.New("Error parsing rule: " + rule)
|
||||||
}
|
}
|
||||||
parsedFunction, ok := functions[parsedFunctions[0]]
|
parsedFunction, ok := functions[parsedFunctions[0]]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("Error parsing rule: " + expression + ". Unknown function: " + parsedFunctions[0])
|
return nil, errors.New("Error parsing rule: " + rule + ". Unknown function: " + parsedFunctions[0])
|
||||||
}
|
}
|
||||||
parsedFunctions = append(parsedFunctions[:0], parsedFunctions[1:]...)
|
parsedFunctions = append(parsedFunctions[:0], parsedFunctions[1:]...)
|
||||||
fargs := func(c rune) bool {
|
fargs := func(c rune) bool {
|
||||||
return c == ',' || c == ';'
|
return c == ','
|
||||||
}
|
}
|
||||||
// get function
|
// get function
|
||||||
parsedArgs := strings.FieldsFunc(strings.Join(parsedFunctions, ":"), fargs)
|
parsedArgs := strings.FieldsFunc(strings.Join(parsedFunctions, ":"), fargs)
|
||||||
if len(parsedArgs) == 0 {
|
if len(parsedArgs) == 0 {
|
||||||
return nil, errors.New("Error parsing args from rule: " + expression)
|
return nil, errors.New("Error parsing args from rule: " + rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs := make([]reflect.Value, len(parsedArgs))
|
inputs := make([]reflect.Value, len(parsedArgs))
|
||||||
|
@ -134,14 +145,17 @@ func (r *Rules) Parse(expression string) (*mux.Route, error) {
|
||||||
}
|
}
|
||||||
method := reflect.ValueOf(parsedFunction)
|
method := reflect.ValueOf(parsedFunction)
|
||||||
if method.IsValid() {
|
if method.IsValid() {
|
||||||
resultRoute := method.Call(inputs)[0].Interface().(*mux.Route)
|
resultRoute = method.Call(inputs)[0].Interface().(*mux.Route)
|
||||||
if r.err != nil {
|
if r.err != nil {
|
||||||
return nil, r.err
|
return nil, r.err
|
||||||
}
|
}
|
||||||
if resultRoute.GetError() != nil {
|
if resultRoute.GetError() != nil {
|
||||||
return nil, resultRoute.GetError()
|
return nil, resultRoute.GetError()
|
||||||
}
|
}
|
||||||
return resultRoute, nil
|
|
||||||
}
|
} else {
|
||||||
return nil, errors.New("Method not found: " + parsedFunctions[0])
|
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"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/negroni"
|
"github.com/codegangsta/negroni"
|
||||||
|
"github.com/containous/mux"
|
||||||
"github.com/containous/oxy/cbreaker"
|
"github.com/containous/oxy/cbreaker"
|
||||||
"github.com/containous/oxy/connlimit"
|
"github.com/containous/oxy/connlimit"
|
||||||
"github.com/containous/oxy/forward"
|
"github.com/containous/oxy/forward"
|
||||||
|
@ -30,7 +31,6 @@ import (
|
||||||
"github.com/containous/traefik/provider"
|
"github.com/containous/traefik/provider"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/mailgun/manners"
|
"github.com/mailgun/manners"
|
||||||
"github.com/streamrail/concurrent-map"
|
"github.com/streamrail/concurrent-map"
|
||||||
)
|
)
|
||||||
|
@ -501,6 +501,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Reusing backend %s", frontend.Backend)
|
log.Debugf("Reusing backend %s", frontend.Backend)
|
||||||
}
|
}
|
||||||
|
if frontend.Priority > 0 {
|
||||||
|
newServerRoute.route.Priority(frontend.Priority)
|
||||||
|
}
|
||||||
server.wireFrontendBackend(newServerRoute, backends[frontend.Backend])
|
server.wireFrontendBackend(newServerRoute, backends[frontend.Backend])
|
||||||
}
|
}
|
||||||
err := newServerRoute.route.GetError()
|
err := newServerRoute.route.GetError()
|
||||||
|
@ -511,6 +514,10 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
middlewares.SetBackend2FrontendMap(&backend2FrontendMap)
|
middlewares.SetBackend2FrontendMap(&backend2FrontendMap)
|
||||||
|
//sort routes
|
||||||
|
for _, serverEntryPoint := range serverEntryPoints {
|
||||||
|
serverEntryPoint.httpRouter.GetHandler().SortRoutes()
|
||||||
|
}
|
||||||
return serverEntryPoints, nil
|
return serverEntryPoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,6 +583,7 @@ func getRoute(serverRoute *serverRoute, route *types.Route) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
newRoute.Priority(serverRoute.route.GetPriority() + len(route.Rule))
|
||||||
serverRoute.route = newRoute
|
serverRoute.route = newRoute
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
[frontends.frontend-{{.ServiceName}}]
|
[frontends.frontend-{{.ServiceName}}]
|
||||||
backend = "backend-{{.ServiceName}}"
|
backend = "backend-{{.ServiceName}}"
|
||||||
passHostHeader = {{getAttribute "frontend.passHostHeader" .Attributes "true"}}
|
passHostHeader = {{getAttribute "frontend.passHostHeader" .Attributes "true"}}
|
||||||
|
priority = {{getAttribute "frontend.priority" .Attributes "0"}}
|
||||||
{{$entryPoints := getAttribute "frontend.entrypoints" .Attributes ""}}
|
{{$entryPoints := getAttribute "frontend.entrypoints" .Attributes ""}}
|
||||||
{{with $entryPoints}}
|
{{with $entryPoints}}
|
||||||
entrypoints = [{{range getEntryPoints $entryPoints}}
|
entrypoints = [{{range getEntryPoints $entryPoints}}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
[frontends."frontend-{{$frontend}}"]{{$container := index $containers 0}}
|
[frontends."frontend-{{$frontend}}"]{{$container := index $containers 0}}
|
||||||
backend = "backend-{{getBackend $container}}"
|
backend = "backend-{{getBackend $container}}"
|
||||||
passHostHeader = {{getPassHostHeader $container}}
|
passHostHeader = {{getPassHostHeader $container}}
|
||||||
|
priority = {{getPriority $container}}
|
||||||
entryPoints = [{{range getEntryPoints $container}}
|
entryPoints = [{{range getEntryPoints $container}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{end}}]
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
[frontends."{{$frontend}}"]
|
[frontends."{{$frontend}}"]
|
||||||
backend = "{{Get "" . "/backend"}}"
|
backend = "{{Get "" . "/backend"}}"
|
||||||
passHostHeader = {{Get "true" . "/passHostHeader"}}
|
passHostHeader = {{Get "true" . "/passHostHeader"}}
|
||||||
|
priority = {{Get "0" . "/priority"}}
|
||||||
entryPoints = [{{range $entryPoints}}
|
entryPoints = [{{range $entryPoints}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{end}}]
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
[frontends.frontend{{.ID | replace "/" "-"}}]
|
[frontends.frontend{{.ID | replace "/" "-"}}]
|
||||||
backend = "backend{{getFrontendBackend .}}"
|
backend = "backend{{getFrontendBackend .}}"
|
||||||
passHostHeader = {{getPassHostHeader .}}
|
passHostHeader = {{getPassHostHeader .}}
|
||||||
|
priority = {{getPriority .}}
|
||||||
entryPoints = [{{range getEntryPoints .}}
|
entryPoints = [{{range getEntryPoints .}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{end}}]
|
||||||
|
|
|
@ -103,7 +103,7 @@ Complete documentation is available at https://traefik.io`,
|
||||||
s.AddSource(toml)
|
s.AddSource(toml)
|
||||||
s.AddSource(f)
|
s.AddSource(f)
|
||||||
if _, err := s.LoadConfig(); err != nil {
|
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()
|
traefikConfiguration.ConfigFile = toml.ConfigFileUsed()
|
||||||
|
|
|
@ -34,7 +34,7 @@ type CircuitBreaker struct {
|
||||||
// Server holds server configuration.
|
// Server holds server configuration.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
Weight int `json:"weight,omitempty"`
|
Weight int `json:"weight"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Route holds route configuration.
|
// Route holds route configuration.
|
||||||
|
@ -52,6 +52,7 @@ type Frontend struct {
|
||||||
Backend string `json:"backend,omitempty"`
|
Backend string `json:"backend,omitempty"`
|
||||||
Routes map[string]Route `json:"routes,omitempty"`
|
Routes map[string]Route `json:"routes,omitempty"`
|
||||||
PassHostHeader bool `json:"passHostHeader,omitempty"`
|
PassHostHeader bool `json:"passHostHeader,omitempty"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadBalancerMethod holds the method of load balancing to use.
|
// LoadBalancerMethod holds the method of load balancing to use.
|
||||||
|
|
2
web.go
2
web.go
|
@ -9,11 +9,11 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/containous/mux"
|
||||||
"github.com/containous/traefik/autogen"
|
"github.com/containous/traefik/autogen"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/elazarl/go-bindata-assetfs"
|
"github.com/elazarl/go-bindata-assetfs"
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/thoas/stats"
|
"github.com/thoas/stats"
|
||||||
"github.com/unrolled/render"
|
"github.com/unrolled/render"
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div data-bg-show="frontendCtrl.frontend.backend" class="panel-footer">
|
<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 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 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.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>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue