Compare commits

...

8 Commits

Author SHA1 Message Date
Vincent Demeester
11781087ca Merge pull request #230 from tayzlor/marathon-event-stream
Use event stream API instead of event subscriptions
2016-03-02 15:24:43 +01:00
Graham Taylor
3063251d43 Use event stream API instead of event subscriptions 2016-03-02 09:22:14 +00:00
Vincent Demeester
b42b170ad2 Merge pull request #227 from containous/fix-docker-network
Fix docker network
2016-03-01 13:12:08 +01:00
Emile Vauge
defbb44b35 Fix docker network
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-03-01 11:52:30 +00:00
Emile Vauge
a00eb81f03 Merge pull request #228 from ProPheT777/patch-1
My $0.02 - Center gopher
2016-02-29 19:35:47 +01:00
Johann Saunier
a63d989a35 My $0.02 - Center gopher 2016-02-29 18:27:09 +01:00
Vincent Demeester
6c3c5578c6 Merge pull request #225 from containous/add-path-prefix
Add PathPrefixStrip and PathStrip rules
2016-02-26 16:52:12 +01:00
Emile Vauge
122783e36b Add PathPrefixStrip and PathStrip rules
Signed-off-by: Emile Vauge <emile@vauge.com>
2016-02-26 15:58:55 +01:00
12 changed files with 114 additions and 69 deletions

View File

@@ -1,5 +1,7 @@
![Træfɪk](http://traefik.github.io/traefik.logo.svg "Træfɪk")
___
<p align="center">
<img src="http://traefik.github.io/traefik.logo.svg" alt="Træfɪk" title="Træfɪk" />
</p>
[![Build Status](https://travis-ci.org/containous/traefik.svg?branch=master)](https://travis-ci.org/containous/traefik)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/containous/traefik/blob/master/LICENSE.md)

1
cmd.go
View File

@@ -126,7 +126,6 @@ func init() {
traefikCmd.PersistentFlags().StringVar(&arguments.Marathon.Filename, "marathon.filename", "", "Override default configuration template. For advanced users :)")
traefikCmd.PersistentFlags().StringVar(&arguments.Marathon.Endpoint, "marathon.endpoint", "http://127.0.0.1:8080", "Marathon server endpoint. You can also specify multiple endpoint for Marathon")
traefikCmd.PersistentFlags().StringVar(&arguments.Marathon.Domain, "marathon.domain", "", "Default domain used")
traefikCmd.PersistentFlags().StringVar(&arguments.Marathon.NetworkInterface, "marathon.networkInterface", "eth0", "Network interface used to call Marathon web services. Needed in case of multiple network interfaces")
traefikCmd.PersistentFlags().BoolVar(&arguments.consul, "consul", false, "Enable Consul backend")
traefikCmd.PersistentFlags().BoolVar(&arguments.Consul.Watch, "consul.watch", true, "Watch provider")

View File

@@ -37,7 +37,9 @@ Frontends can be defined using the following rules:
- `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]+}`
- `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.
- `PathPrefixStrip`: Same as `PathPrefix` but strip the given prefix from the request URL's Path.
A frontend is a set of rules that forwards the incoming http traffic to a backend.
@@ -149,7 +151,6 @@ Flags:
--marathon.domain string Default domain used
--marathon.endpoint string Marathon server endpoint. You can also specify multiple endpoint for Marathon (default "http://127.0.0.1:8080")
--marathon.filename string Override default configuration template. For advanced users :)
--marathon.networkInterface string Network interface used to call Marathon web services. Needed in case of multiple network interfaces (default "eth0")
--marathon.watch Watch provider (default true)
--maxIdleConnsPerHost int If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used
--providersThrottleDuration duration Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time. (default 2s)
@@ -638,12 +639,6 @@ Træfɪk can be configured to use Marathon as a backend configuration:
#
endpoint = "http://127.0.0.1:8080"
# Network interface used to call Marathon web services. Needed in case of multiple network interfaces.
# Optional
# Default: "eth0"
#
networkInterface = "eth0"
# Enable watch Marathon changes
#
# Optional

View File

@@ -57,7 +57,7 @@ import:
- package: github.com/flynn/go-shlex
ref: 3f9db97f856818214da2e1057f8ad84803971cff
- package: github.com/fsouza/go-dockerclient
ref: 0239034d42f665efa17fd77c39f891c2f9f32922
ref: a49c8269a6899cae30da1f8a4b82e0ce945f9967
- package: github.com/boltdb/bolt
ref: 51f99c862475898df9773747d3accd05a7ca33c1
- package: gopkg.in/mgo.v2

View File

@@ -0,0 +1,22 @@
package middlewares
import (
"net/http"
"strings"
)
// StripPrefix is a middleware used to strip prefix from an URL request
type StripPrefix struct {
Handler http.Handler
Prefix 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)
}
}

View File

@@ -676,7 +676,11 @@ func TestDockerLoadDockerConfig(t *testing.T) {
Ports: map[docker.Port][]docker.PortBinding{
"80/tcp": {},
},
IPAddress: "127.0.0.1",
Networks: map[string]docker.ContainerNetwork{
"bridgde": {
IPAddress: "127.0.0.1",
},
},
},
},
},
@@ -718,7 +722,11 @@ func TestDockerLoadDockerConfig(t *testing.T) {
Ports: map[docker.Port][]docker.PortBinding{
"80/tcp": {},
},
IPAddress: "127.0.0.1",
Networks: map[string]docker.ContainerNetwork{
"bridgde": {
IPAddress: "127.0.0.1",
},
},
},
},
{
@@ -732,7 +740,11 @@ func TestDockerLoadDockerConfig(t *testing.T) {
Ports: map[docker.Port][]docker.PortBinding{
"80/tcp": {},
},
IPAddress: "127.0.0.1",
Networks: map[string]docker.ContainerNetwork{
"bridgde": {
IPAddress: "127.0.0.1",
},
},
},
},
},

View File

@@ -17,13 +17,12 @@ import (
// Marathon holds configuration of the Marathon provider.
type Marathon struct {
BaseProvider `mapstructure:",squash"`
Endpoint string
Domain string
NetworkInterface string
Basic *MarathonBasic
TLS *tls.Config
marathonClient marathon.Marathon
BaseProvider `mapstructure:",squash"`
Endpoint string
Domain string
Basic *MarathonBasic
TLS *tls.Config
marathonClient marathon.Marathon
}
// MarathonBasic holds basic authentication specific configurations
@@ -42,7 +41,7 @@ type lightMarathonClient interface {
func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage) error {
config := marathon.NewDefaultConfig()
config.URL = provider.Endpoint
config.EventsInterface = provider.NetworkInterface
config.EventsTransport = marathon.EventsTransportSSE
if provider.Basic != nil {
config.HTTPBasicAuthUser = provider.Basic.HTTPBasicAuthUser
config.HTTPBasicPassword = provider.Basic.HTTPBasicPassword
@@ -61,7 +60,7 @@ func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage)
update := make(marathon.EventsChannel, 5)
if provider.Watch {
if err := client.AddEventsListener(update, marathon.EVENTS_APPLICATIONS); err != nil {
log.Errorf("Failed to register for subscriptions, %s", err)
log.Errorf("Failed to register for events, %s", err)
} else {
go func() {
for {

View File

@@ -31,9 +31,9 @@ git push --follow-tags -u origin master
# create docker image emilevauge/traefik (compatibility)
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
docker push ${REPO,,}:latest
docker tag ${REPO,,}:latest ${REPO,,}:${VERSION}
docker push ${REPO,,}:${VERSION}
docker push emilevauge/traefik:latest
docker tag emilevauge/traefik:latest emilevauge/traefik:${VERSION}
docker push emilevauge/traefik:${VERSION}
cd ..
rm -Rf traefik-library-image/

View File

@@ -7,6 +7,16 @@ import (
"crypto/tls"
"encoding/json"
"errors"
"net/http"
"net/url"
"os"
"os/signal"
"reflect"
"regexp"
"sort"
"sync"
"syscall"
"time"
log "github.com/Sirupsen/logrus"
"github.com/codegangsta/negroni"
@@ -18,16 +28,6 @@ import (
"github.com/mailgun/oxy/cbreaker"
"github.com/mailgun/oxy/forward"
"github.com/mailgun/oxy/roundrobin"
"net/http"
"net/url"
"os"
"os/signal"
"reflect"
"regexp"
"sort"
"sync"
"syscall"
"time"
)
var oxyLogger = &OxyLogger{}
@@ -335,11 +335,11 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
newRoute := serverEntryPoints[entryPointName].httpRouter.NewRoute().Name(frontendName)
for routeName, route := range frontend.Routes {
log.Debugf("Creating route %s %s:%s", routeName, route.Rule, route.Value)
newRouteReflect, err := invoke(newRoute, route.Rule, route.Value)
route, err := getRoute(newRoute, route.Rule, route.Value)
if err != nil {
return nil, err
}
newRoute = newRouteReflect[0].Interface().(*mux.Route)
newRoute = route
}
entryPoint := globalConfiguration.EntryPoints[entryPointName]
if entryPoint.Redirect != nil {
@@ -399,7 +399,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
} else {
log.Debugf("Reusing backend %s", frontend.Backend)
}
newRoute.Handler(backends[frontend.Backend])
server.wireFrontendBackend(frontend.Routes, newRoute, backends[frontend.Backend])
}
err := newRoute.GetError()
if err != nil {
@@ -411,6 +411,32 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
return serverEntryPoints, nil
}
func (server *Server) wireFrontendBackend(routes map[string]types.Route, newRoute *mux.Route, handler http.Handler) {
// strip prefix
var strip bool
for _, route := range routes {
switch route.Rule {
case "PathStrip":
newRoute.Handler(&middlewares.StripPrefix{
Prefix: route.Value,
Handler: handler,
})
strip = true
break
case "PathPrefixStrip":
newRoute.Handler(&middlewares.StripPrefix{
Prefix: route.Value,
Handler: handler,
})
strip = true
break
}
}
if !strip {
newRoute.Handler(handler)
}
}
func (server *Server) loadEntryPointConfig(entryPointName string, entryPoint *EntryPoint) (http.Handler, error) {
regex := entryPoint.Redirect.Regex
replacement := entryPoint.Redirect.Replacement
@@ -443,9 +469,28 @@ func (server *Server) loadEntryPointConfig(entryPointName string, entryPoint *En
func (server *Server) buildDefaultHTTPRouter() *mux.Router {
router := mux.NewRouter()
router.NotFoundHandler = http.HandlerFunc(notFoundHandler)
router.StrictSlash(true)
return router
}
func getRoute(any interface{}, rule string, value ...interface{}) (*mux.Route, error) {
switch rule {
case "PathStrip":
rule = "Path"
case "PathPrefixStrip":
rule = "PathPrefix"
}
inputs := make([]reflect.Value, len(value))
for i := range value {
inputs[i] = reflect.ValueOf(value[i])
}
method := reflect.ValueOf(any).MethodByName(rule)
if method.IsValid() {
return method.Call(inputs)[0].Interface().(*mux.Route), nil
}
return nil, errors.New("Method not found: " + rule)
}
func sortedFrontendNamesForConfig(configuration *types.Configuration) []string {
keys := []string{}

View File

@@ -1,6 +1,6 @@
[backends]{{range .Containers}}
[backends.backend-{{getBackend .}}.servers.server-{{.Name | replace "/" "" | replace "." "-"}}]
url = "{{getProtocol .}}://{{.NetworkSettings.IPAddress}}:{{getPort .}}"
url = "{{getProtocol .}}://{{range $i := .NetworkSettings.Networks}}{{if $i}}{{.IPAddress}}{{end}}{{end}}:{{getPort .}}"
weight = {{getWeight .}}
{{end}}

View File

@@ -206,12 +206,6 @@
#
# endpoint = "http://127.0.0.1:8080"
# Network interface used to call Marathon web services. Needed in case of multiple network interfaces.
# Optional
# Default: "eth0"
#
# networkInterface = "eth0"
# Enable watch Marathon changes
#
# Optional

View File

@@ -1,23 +0,0 @@
/*
Copyright
*/
package main
import (
"errors"
"reflect"
)
// Invoke calls the specified method with the specified arguments on the specified interface.
// It uses the go(lang) reflect package.
func invoke(any interface{}, name string, args ...interface{}) ([]reflect.Value, error) {
inputs := make([]reflect.Value, len(args))
for i := range args {
inputs[i] = reflect.ValueOf(args[i])
}
method := reflect.ValueOf(any).MethodByName(name)
if method.IsValid() {
return method.Call(inputs), nil
}
return nil, errors.New("Method not found: " + name)
}