Compare commits

..

20 Commits

Author SHA1 Message Date
Emile Vauge
f99f634816 Merge pull request #290 from containous/fix-issues
Fix issues
2016-04-07 16:36:13 +02:00
Emile Vauge
5292a5b9d4 Migrate to official docker image
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-07 16:24:11 +02:00
Emile Vauge
cf22d62a74 Fix mkdoc deploy
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-07 16:24:11 +02:00
Emile Vauge
9363e2ab83 Fix broken table in webUI
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-07 16:24:11 +02:00
Emile Vauge
e5ddd92677 Fix port support in host rule
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-07 16:23:57 +02:00
Vincent Demeester
04628056af Merge pull request #287 from containous/fix-doc-deploy
Fix doc deploy...
2016-04-06 19:17:50 +02:00
Emile Vauge
dada86c0b0 Fix doc deploy...
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-06 18:50:35 +02:00
Vincent Demeester
92c269c972 Merge pull request #286 from containous/fix-CI-env-variable
Fix CI env variable...
2016-04-06 17:45:34 +02:00
Emile Vauge
6991e3c99b Fix CI env variable...
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-06 17:31:43 +02:00
Vincent Demeester
3ee3daee00 Merge pull request #285 from containous/add-multiple-rules
Add multiple rules
2016-04-06 16:24:16 +02:00
Emile Vauge
85fcff4cf7 Multiple rules docs
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-06 16:10:20 +02:00
Emile Vauge
30db47d9b6 Fix SSH key, I hope...
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-06 15:28:25 +02:00
Emile Vauge
4d2c85ffdc Fix multiple response.WriteHeader calls
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-06 14:30:29 +02:00
Emile Vauge
e36433c23a Fix retry attempts
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-06 14:07:51 +02:00
Emile Vauge
8486766a60 Add multiple rules
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-06 13:27:54 +02:00
Vincent Demeester
ef72d355d6 Merge pull request #283 from containous/fix-openssl-travis
Fix SSH key
2016-04-06 00:46:30 +02:00
Emile Vauge
7d013ad5e8 Fix SSH key
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-05 22:40:42 +02:00
Vincent Demeester
5fcce6567e Merge pull request #282 from containous/fix-openssl-travis
Fix openssl travis
2016-04-05 22:24:25 +02:00
Emile Vauge
00af537b0d Fix link in README
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-05 22:07:16 +02:00
Emile Vauge
78449fa62f Fix openssl load key in CI
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-04-05 20:47:23 +02:00
13 changed files with 158 additions and 73 deletions

View File

@@ -1,22 +1,14 @@
branches:
except:
- /^v\d\.\d\.\d.*$/
env:
REPO: $TRAVIS_REPO_SLUG
VERSION: v1.0.0-beta.$TRAVIS_BUILD_NUMBER
global:
- secure: btt4r13t09gQlHb6gYrvGC2yGCMMHfnp1Mz1RQedc4Mpf/FfT8aE6xmK2a2i9CCvskjrP0t/BFaS4yxIURjnFRn+ugQIEa0pLspB9UJArW/vgOSpIWM9/OQ/fg8z5XuMxN6Md4DL1/iLypMNSageA1x0TRdt89+D1N1dALpg5XRCXLFbC84TLi0gjlFuib9ibPKzEhLT+anCRJ6iZMzeupDSoaCVbAtJMoDvXw4+4AcRZ1+k4MybBLyCib5boaEOt4pTT88mz4Kk0YaMwPVJyg9Qv36VqyUcPS09Yd95LuyVQ4+tZt8Y1ccbIzULsK+sLM3hLCzxlmlpN3dQBlZJiiRtQde0mgGAKyC0P0A1XjuDTywcsa5edB+fTk1Dsewz9xZ9V0NmMz8t+UNZnaSsAPga9i86jULbXUUwMVSzVRc+Xgx02liB/8qI1xYC9FM6ilStt7rn7mF0k3KbiWhcptgeXjO6Lah9FjEKd5w4MXsdUSTi/86rQaLo+kj+XdaTrXCTulKHyRyQEUj+8V1w0oVz7pcGjePHd7y5oU9ByifVQy6sytuFBfRZvugM5bKHo+i0pcWvixrZS42DrzwxZJsspANOvqSe5ifVbvOkfUppQdCBIwptxV5N1b49XPKU3W/w34QJ8xGmKp3TFA7WwVCztriFHjPgiRpB3EG99Bg=
- REPO: $TRAVIS_REPO_SLUG
- VERSION: v1.0.0-beta.$TRAVIS_BUILD_NUMBER
sudo: required
services:
- docker
before_install:
- openssl aes-256-cbc -K $encrypted_27087ae1f4db_key -iv $encrypted_27087ae1f4db_iv -in .travis/traefik.id_rsa.enc -out ~/.ssh/traefik.id_rsa -d
- eval "$(ssh-agent -s)"
- chmod 600 ~/.ssh/traefik.id_rsa
- ssh-add ~/.ssh/traefik.id_rsa
install:
- sudo service docker stop
- sudo curl https://get.docker.com/builds/Linux/x86_64/docker-1.10.1 -o /usr/bin/docker
@@ -24,16 +16,13 @@ install:
- sudo service docker start
- pip install --user mkdocs
- pip install --user pymdown-extensions
before_script:
- make validate
- make binary
script:
- make test-unit
- make test-integration
- make crossbinary
- make image
after_success:
- make deploy
- make deploy

Binary file not shown.

View File

@@ -6,6 +6,7 @@
[![Build Status](https://travis-ci.org/containous/traefik.svg?branch=master)](https://travis-ci.org/containous/traefik)
[![Docs](https://img.shields.io/badge/docs-current-brightgreen.svg)](https://docs.traefik.io)
[![Go Report Card](https://goreportcard.com/badge/kubernetes/helm)](http://goreportcard.com/report/containous/traefik)
[![Image Layer](https://badge.imagelayers.io/traefik:latest.svg)](https://imagelayers.io/?images=traefik)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/containous/traefik/blob/master/LICENSE.md)
[![Join the chat at https://traefik.herokuapp.com](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://traefik.herokuapp.com)
[![Twitter](https://img.shields.io/twitter/follow/traefikproxy.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefikproxy)
@@ -41,7 +42,7 @@ Run it and forget it!
## Features
- [It's fast](docs/index.md#benchmarks)
- [It's fast](http://docs.traefik.io/benchmarks)
- No dependency hell, single binary made with go
- Rest API
- Multiple backends supported: Docker, Mesos/Marathon, Consul, Etcd, and more to come
@@ -51,7 +52,7 @@ Run it and forget it!
- Circuit breakers on backends
- Round Robin, rebalancer load-balancers
- Rest Metrics
- Tiny docker image included [![Image Layers](https://badge.imagelayers.io/containous/traefik:latest.svg)](https://imagelayers.io/?images=containous/traefik:latest)
- [Tiny](https://imagelayers.io/?images=traefik) [official](https://hub.docker.com/r/_/traefik/) docker image included
- SSL backends support
- SSL frontend support (with SNI)
- Clean AngularJS Web UI
@@ -92,7 +93,7 @@ You can access to a simple HTML frontend of Træfik.
- Use the tiny Docker image:
```shell
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/etc/traefik/traefik.toml containous/traefik
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/etc/traefik/traefik.toml traefik
```
- From sources:

View File

@@ -59,13 +59,14 @@ Here is an example of entrypoints definition:
A frontend is a set of rules that forwards the incoming traffic from an entrypoint to a backend.
Frontends can be defined using the following rules:
- `Headers`: Headers adds a matcher for request header values. It accepts a sequence of key/value pairs to be matched. For example: `Content-Type, application/json`
- `HeadersRegexp`: Regular expressions can be used with headers as well. It accepts a sequence of key/value pairs, where the value has regex support. For example: `Content-Type, application/(text|json)`
- `Host`: Host adds a matcher for the URL host. It accepts a template with zero or more URL variables enclosed by `{}`. Variables can define an optional regexp pattern to be matched: `www.traefik.io`, `{subdomain:[a-z]+}.traefik.io`
- `Methods`: Methods adds a matcher for HTTP methods. It accepts a sequence of one or more methods to be matched, e.g.: `GET`, `POST`, `PUT`
- `Path`: Path adds a matcher for the URL path. It accepts a template with zero or more URL variables enclosed by `{}`. The template must start with a `/`. For exemple `/products/` `/articles/{category}/{id:[0-9]+}`
- `Headers: Content-Type, application/json`: Headers adds a matcher for request header values. It accepts a sequence of key/value pairs to be matched.
- `HeadersRegexp: Content-Type, application/(text|json)`: Regular expressions can be used with headers as well. It accepts a sequence of key/value pairs, where the value has regex support.
- `Host: traefik.io, www.traefik.io`: Match request host with given host list.
- `HostRegexp: traefik.io, {subdomain:[a-z]+}.traefik.io`: Adds a matcher for the URL hosts. It accepts templates with zero or more URL variables enclosed by `{}`. Variables can define an optional regexp pattern to be matched.
- `Method: GET, POST, PUT`: Method adds a matcher for HTTP methods. It accepts a sequence of one or more methods to be matched.
- `Path: /products/, /articles/{category}/{id:[0-9]+}`: Path adds a matcher for the URL paths. It accepts templates with zero or more URL variables enclosed by `{}`.
- `PathStrip`: Same as `Path` but strip the given prefix from the request URL's Path.
- `PathPrefix`: PathPrefix adds a matcher for the URL path prefix. 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.
You can optionally enable `passHostHeader` to forward client `Host` header to the backend.
@@ -77,21 +78,21 @@ Here is an example of frontends definition:
[frontends.frontend1]
backend = "backend2"
[frontends.frontend1.routes.test_1]
rule = "Host:test.localhost"
rule = "Host: test.localhost, test2.localhost"
[frontends.frontend2]
backend = "backend1"
passHostHeader = true
entrypoints = ["https"] # overrides defaultEntryPoints
[frontends.frontend2.routes.test_1]
rule = "Host:{subdomain:[a-z]+}.localhost"
rule = "Host: localhost, {subdomain:[a-z]+}.localhost"
[frontends.frontend3]
backend = "backend2"
rule = "Path:/test"
```
- Three frontends are defined: `frontend1`, `frontend2` and `frontend3`
- `frontend1` will forward the traffic to the `backend2` if the rule `Host:test.localhost` is matched
- `frontend2` will forward the traffic to the `backend1` if the rule `Host:{subdomain:[a-z]+}.localhost` is matched (forwarding client `Host` header to the backend)
- `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
## Backends

View File

@@ -52,7 +52,7 @@ Transfer/sec: 0.99MB
```sh
$ docker run -d -l traefik.backend=test1 -l traefik.frontend.rule=Host -l traefik.frontend.value=test.traefik.localhost emilevauge/whoami
$ docker run -d -l traefik.backend=test1 -l traefik.frontend.rule=Host -l traefik.frontend.value=test.traefik.localhost emilevauge/whoami
$ docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/traefik.toml -v /var/run/docker.sock:/var/run/docker.sock containous/traefik
$ docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/traefik.toml -v /var/run/docker.sock:/var/run/docker.sock traefik
$ wrk -t12 -c400 -d60s -H "Host: test.traefik.localhost" --latency http://127.0.0.1:80
Running 1m test @ http://127.0.0.1:80
12 threads and 400 connections

View File

@@ -57,7 +57,7 @@ You can grab the latest binary from the [releases](https://github.com/containous
Using the tiny Docker image:
```shell
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/etc/traefik/traefik.toml containous/traefik
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.toml:/etc/traefik/traefik.toml traefik
```
## Test it
@@ -66,7 +66,7 @@ You can test Træfɪk easily using [Docker compose](https://docs.docker.com/comp
```yaml
traefik:
image: containous/traefik
image: traefik
command: --web --docker --docker.domain=docker.localhost --logLevel=DEBUG
ports:
- "80:80"

View File

@@ -1,5 +1,5 @@
traefik:
image: containous/traefik
image: traefik
command: --web --docker --docker.domain=docker.localhost --logLevel=DEBUG
ports:
- "80:80"

View File

@@ -7,18 +7,20 @@ import (
// StripPrefix is a middleware used to strip prefix from an URL request
type StripPrefix struct {
Handler http.Handler
Prefix string
Handler http.Handler
Prefixes []string
}
func (s *StripPrefix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if p := strings.TrimPrefix(r.URL.Path, s.Prefix); len(p) < len(r.URL.Path) {
r.URL.Path = p
r.RequestURI = r.URL.RequestURI()
s.Handler.ServeHTTP(w, r)
} else {
http.NotFound(w, r)
for _, prefix := range s.Prefixes {
if p := strings.TrimPrefix(r.URL.Path, strings.TrimSpace(prefix)); len(p) < len(r.URL.Path) {
r.URL.Path = p
r.RequestURI = r.URL.RequestURI()
s.Handler.ServeHTTP(w, r)
return
}
}
http.NotFound(w, r)
}
// SetHandler sets handler

View File

@@ -3,35 +3,82 @@ package main
import (
"errors"
"github.com/gorilla/mux"
"net"
"net/http"
"reflect"
"sort"
"strings"
)
// Rules holds rule parsing and configuration
type Rules struct {
route *serverRoute
err error
}
func (r *Rules) host(host string) *mux.Route {
return r.route.route.Host(host)
func (r *Rules) host(hosts ...string) *mux.Route {
return r.route.route.MatcherFunc(func(req *http.Request, route *mux.RouteMatch) bool {
reqHost, _, err := net.SplitHostPort(req.Host)
if err != nil {
reqHost = req.Host
}
for _, host := range hosts {
if reqHost == strings.TrimSpace(host) {
return true
}
}
return false
})
}
func (r *Rules) path(path string) *mux.Route {
return r.route.route.Path(path)
func (r *Rules) hostRegexp(hosts ...string) *mux.Route {
router := r.route.route.Subrouter()
for _, host := range hosts {
router.Host(strings.TrimSpace(host))
}
return r.route.route
}
func (r *Rules) pathPrefix(path string) *mux.Route {
return r.route.route.PathPrefix(path)
func (r *Rules) path(paths ...string) *mux.Route {
router := r.route.route.Subrouter()
for _, path := range paths {
router.Path(strings.TrimSpace(path))
}
return r.route.route
}
func (r *Rules) pathStrip(path string) *mux.Route {
r.route.stripPrefix = path
return r.route.route.Path(path)
func (r *Rules) pathPrefix(paths ...string) *mux.Route {
router := r.route.route.Subrouter()
for _, path := range paths {
router.PathPrefix(strings.TrimSpace(path))
}
return r.route.route
}
func (r *Rules) pathPrefixStrip(path string) *mux.Route {
r.route.stripPrefix = path
return r.route.route.PathPrefix(path)
type bySize []string
func (a bySize) Len() int { return len(a) }
func (a bySize) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a bySize) Less(i, j int) bool { return len(a[i]) > len(a[j]) }
func (r *Rules) pathStrip(paths ...string) *mux.Route {
sort.Sort(bySize(paths))
r.route.stripPrefixes = paths
router := r.route.route.Subrouter()
for _, path := range paths {
router.Path(strings.TrimSpace(path))
}
return r.route.route
}
func (r *Rules) pathPrefixStrip(paths ...string) *mux.Route {
sort.Sort(bySize(paths))
r.route.stripPrefixes = paths
router := r.route.route.Subrouter()
for _, path := range paths {
router.PathPrefix(strings.TrimSpace(path))
}
return r.route.route
}
func (r *Rules) methods(methods ...string) *mux.Route {
@@ -50,32 +97,33 @@ func (r *Rules) headersRegexp(headers ...string) *mux.Route {
func (r *Rules) Parse(expression string) (*mux.Route, error) {
functions := map[string]interface{}{
"Host": r.host,
"HostRegexp": r.hostRegexp,
"Path": r.path,
"PathStrip": r.pathStrip,
"PathPrefix": r.pathPrefix,
"PathPrefixStrip": r.pathPrefixStrip,
"Methods": r.methods,
"Method": r.methods,
"Headers": r.headers,
"HeadersRegexp": r.headersRegexp,
}
f := func(c rune) bool {
return c == ':' || c == '='
return c == ':'
}
// get function
parsedFunctions := strings.FieldsFunc(expression, f)
if len(parsedFunctions) != 2 {
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 + ". Unknow function: " + parsedFunctions[0])
}
parsedFunctions = append(parsedFunctions[:0], parsedFunctions[1:]...)
fargs := func(c rune) bool {
return c == ',' || c == ';'
}
// get function
parsedArgs := strings.FieldsFunc(parsedFunctions[1], fargs)
parsedArgs := strings.FieldsFunc(strings.Join(parsedFunctions, ":"), fargs)
if len(parsedArgs) == 0 {
return nil, errors.New("Error parsing args from rule: " + expression)
}
@@ -86,7 +134,14 @@ func (r *Rules) Parse(expression string) (*mux.Route, error) {
}
method := reflect.ValueOf(parsedFunction)
if method.IsValid() {
return method.Call(inputs)[0].Interface().(*mux.Route), nil
resultRoute := method.Call(inputs)[0].Interface().(*mux.Route)
if r.err != nil {
return nil, r.err
}
if resultRoute.GetError() != nil {
return nil, resultRoute.GetError()
}
return resultRoute, nil
}
return nil, errors.New("Method not found: " + parsedFunctions[0])
}

View File

@@ -2,35 +2,64 @@
set -e
if ([ "$TRAVIS_BRANCH" = "master" ] || [ ! -z "$TRAVIS_TAG" ]) && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
echo "Deploying"
echo "Deploying..."
else
echo "Skipping deploy"
exit 0
fi
curl -LO https://github.com/tcnksm/ghr/releases/download/pre-release/linux_amd64.zip
git config --global user.email "emile@vauge.com"
git config --global user.name "Emile Vauge"
# load ssh key
echo "Loading key..."
openssl aes-256-cbc -d -k "$pass" -in .travis/traefik.id_rsa.enc -out ~/.ssh/traefik.id_rsa
eval "$(ssh-agent -s)"
chmod 600 ~/.ssh/traefik.id_rsa
ssh-add ~/.ssh/traefik.id_rsa
# download github release
echo "Downloading ghr..."
curl -LOs https://github.com/tcnksm/ghr/releases/download/pre-release/linux_amd64.zip
unzip -q linux_amd64.zip
sudo mv ghr /usr/bin/ghr
sudo chmod +x /usr/bin/ghr
# github release and tag
echo "Github release..."
ghr -t $GITHUB_TOKEN -u containous -r traefik --prerelease ${VERSION} dist/
# update docs.traefik.io
mkdocs gh-deploy --clean
echo "Generating and updating documentation..."
# DOESN'T WORK :'(
# git remote add ssh git@github.com:containous/traefik.git
# mkdocs gh-deploy -m $VERSION -c -r ssh
mkdir site
cd site
git init
git remote add origin git@github.com:containous/traefik.git
git fetch origin
git checkout gh-pages
cd ..
mkdocs build --clean
cd site
git add .
echo $VERSION | git commit --file -
git push -q -f origin gh-pages > /dev/null 2>&1
# update traefik-library-image repo (official Docker image)
git config --global user.email "emile@vauge.com"
git config --global user.name "Emile Vauge"
echo "Updating traefik-library-imag repo..."
git clone git@github.com:containous/traefik-library-image.git
cd traefik-library-image
./update.sh $VERSION
git add -A
echo $VERSION | git commit --file -
echo $VERSION | git tag -a $VERSION --file -
git push -q --follow-tags -u origin master
git push -q --follow-tags -u origin master > /dev/null 2>&1
# create docker image emilevauge/traefik (compatibility)
echo "Updating docker emilevauge/traefik image..."
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
docker tag containous/traefik emilevauge/traefik:latest
docker push emilevauge/traefik:latest

View File

@@ -57,8 +57,8 @@ type serverEntryPoint struct {
}
type serverRoute struct {
route *mux.Route
stripPrefix string
route *mux.Route
stripPrefixes []string
}
// NewServer returns an initialized Server.
@@ -425,7 +425,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
}
// retry ?
if globalConfiguration.Retry != nil {
retries := len(configuration.Backends[frontend.Backend].Servers) - 1
retries := len(configuration.Backends[frontend.Backend].Servers)
if globalConfiguration.Retry.Attempts > 0 {
retries = globalConfiguration.Retry.Attempts
}
@@ -471,10 +471,10 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
func (server *Server) wireFrontendBackend(serverRoute *serverRoute, handler http.Handler) {
// strip prefix
if len(serverRoute.stripPrefix) > 0 {
if len(serverRoute.stripPrefixes) > 0 {
serverRoute.route.Handler(&middlewares.StripPrefix{
Prefix: serverRoute.stripPrefix,
Handler: handler,
Prefixes: serverRoute.stripPrefixes,
Handler: handler,
})
} else {
serverRoute.route.Handler(handler)

View File

@@ -513,7 +513,7 @@
# [frontends.frontend1]
# backend = "backend2"
# [frontends.frontend1.routes.test_1]
# rule = "Host:test.localhost"
# rule = "Host: test.localhost, other.localhost"
# [frontends.frontend2]
# backend = "backend1"
# passHostHeader = true
@@ -523,4 +523,4 @@
# [frontends.frontend3]
# entrypoints = ["http", "https"] # overrides defaultEntryPoints
# backend = "backend2"
# rule = "Path:/test"
# rule = "Path: /test, /other"

View File

@@ -24,3 +24,11 @@
.tabset-row__providers {
margin-top: 3rem;
}
table {
table-layout: fixed;
}
td, th {
word-wrap: break-word;
}