Skip to content

Commit

Permalink
Merge pull request #178 from emilevauge/add-multiple-entrypoints-support
Browse files Browse the repository at this point in the history
Add multiple entry points support
  • Loading branch information
vdemeester committed Feb 10, 2016
2 parents bb3b9f6 + 4152bd5 commit 4ecb919
Show file tree
Hide file tree
Showing 35 changed files with 679 additions and 275 deletions.
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ TRAEFIK_ENVS := \
-e TESTFLAGS \
-e CIRCLECI


SRCS = $(shell git ls-files '*.go' | grep -v '^external/')

BIND_DIR := "dist"
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/emilevauge/traefik/$(BIND_DIR)"

Expand Down Expand Up @@ -78,3 +81,9 @@ generate-webui:
mkdir -p static
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui gulp
echo 'For more informations show `webui/readme.md`' > $$PWD/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md

lint:
$(foreach file,$(SRCS),golint $(file) || exit;)

fmt:
gofmt -s -l -w $(SRCS)
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
![Træfɪk](http://traefik.github.io/traefik.logo.svg "Træfɪk")
___

[![Circle CI](https://circleci.com/gh/emilevauge/traefik.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/emilevauge/traefik)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/EmileVauge/traefik/blob/master/LICENSE.md)
[![Circle CI](https://circleci.com/gh/emilevauge/traefik/tree/master.png?circle-token)](https://circleci.com/gh/emilevauge/traefik)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/EmileVauge/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)


Expand All @@ -22,7 +22,7 @@ It supports several backends ([Docker :whale:](https://www.docker.com/), [Mesos/
- Circuit breakers on backends
- Round Robin, rebalancer load-balancers
- Rest Metrics
- Tiny docker image included
- Tiny docker image included [![Image Layers](https://badge.imagelayers.io/emilevauge/traefik:latest.svg)](https://imagelayers.io/?images=emilevauge/traefik:latest 'Image Layers')
- SSL backends support
- SSL frontend support
- Clean AngularJS Web UI
Expand Down Expand Up @@ -76,6 +76,20 @@ You can find the complete documentation [here](docs/index.md).

Refer to the [benchmarks section](docs/index.md#benchmarks) in the documentation.

## Træfɪk here and there

These projects use Træfɪk internally. If your company uses Træfɪk, we would be glad to get your feedback :) Contact us on [![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)

- Project [Mantl](http://http://mantl.io/) from Cisco

![Web UI Providers](docs/img/mantl-logo.png)
> Mantl is a modern platform for rapidly deploying globally distributed services. A container orchestrator, docker, a network stack, something to pool your logs, something to monitor health, a sprinkle of service discovery and some automation.
- Project [Apollo](http://capgemini.github.io/devops/apollo/) from Cap Gemini

![Web UI Providers](docs/img/apollo-logo.png)
> Apollo is an open source project to aid with building and deploying IAAS and PAAS services. It is particularly geared towards managing containerized applications across multiple hosts, and big data type workloads. Apollo leverages other open source components to provide basic mechanisms for deployment, maintenance, and scaling of infrastructure and applications.
## Contributing

### Building
Expand Down
8 changes: 0 additions & 8 deletions adapters.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"net/http"

log "github.com/Sirupsen/logrus"
"github.com/gorilla/mux"
)

// OxyLogger implements oxy Logger interface with logrus.
Expand All @@ -33,10 +32,3 @@ func notFoundHandler(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
//templatesRenderer.HTML(w, http.StatusNotFound, "notFound", nil)
}

// LoadDefaultConfig returns a default gorrilla.mux router from the specified configuration.
func LoadDefaultConfig(globalConfiguration GlobalConfiguration) *mux.Router {
router := mux.NewRouter()
router.NotFoundHandler = http.HandlerFunc(notFoundHandler)
return router
}
12 changes: 8 additions & 4 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Copyright
package main

import (
"encoding/json"
fmtlog "log"
"os"
"strings"
Expand Down Expand Up @@ -49,6 +50,7 @@ var arguments = struct {
boltdb bool
}{
GlobalConfiguration{
EntryPoints: make(EntryPoints),
Docker: &provider.Docker{
TLS: &provider.DockerTLS{},
},
Expand Down Expand Up @@ -78,7 +80,8 @@ func init() {
traefikCmd.PersistentFlags().StringP("graceTimeOut", "g", "10", "Timeout in seconds. Duration to give active requests a chance to finish during hot-reloads")
traefikCmd.PersistentFlags().String("accessLogsFile", "log/access.log", "Access logs file")
traefikCmd.PersistentFlags().String("traefikLogsFile", "log/traefik.log", "Traefik logs file")
traefikCmd.PersistentFlags().Var(&arguments.Certificates, "certificates", "SSL certificates and keys pair, ie 'tests/traefik.crt,tests/traefik.key'. You may add several certificate/key pairs to terminate HTTPS for multiple domain names using TLS SNI")
traefikCmd.PersistentFlags().Var(&arguments.EntryPoints, "entryPoints", "Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key'")
traefikCmd.PersistentFlags().Var(&arguments.DefaultEntryPoints, "defaultEntryPoints", "Entrypoints to be used by frontends that do not specify any entrypoint")
traefikCmd.PersistentFlags().StringP("logLevel", "l", "ERROR", "Log level")
traefikCmd.PersistentFlags().DurationVar(&arguments.ProvidersThrottleDuration, "providersThrottleDuration", time.Duration(2*time.Second), "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.")
traefikCmd.PersistentFlags().Int("maxIdleConnsPerHost", 0, "If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used")
Expand Down Expand Up @@ -138,13 +141,13 @@ func init() {
viper.BindPFlag("configFile", traefikCmd.PersistentFlags().Lookup("configFile"))
viper.BindPFlag("port", traefikCmd.PersistentFlags().Lookup("port"))
viper.BindPFlag("graceTimeOut", traefikCmd.PersistentFlags().Lookup("graceTimeOut"))
// viper.BindPFlag("certificates", TraefikCmd.PersistentFlags().Lookup("certificates"))
//viper.BindPFlag("defaultEntryPoints", traefikCmd.PersistentFlags().Lookup("defaultEntryPoints"))
viper.BindPFlag("logLevel", traefikCmd.PersistentFlags().Lookup("logLevel"))
// TODO: wait for this issue to be corrected: https://github.com/spf13/viper/issues/105
viper.BindPFlag("providersThrottleDuration", traefikCmd.PersistentFlags().Lookup("providersThrottleDuration"))
viper.BindPFlag("maxIdleConnsPerHost", traefikCmd.PersistentFlags().Lookup("maxIdleConnsPerHost"))
viper.SetDefault("certificates", &Certificates{})
viper.SetDefault("providersThrottleDuration", time.Duration(2*time.Second))
viper.SetDefault("logLevel", "ERROR")
}

func run() {
Expand Down Expand Up @@ -176,7 +179,8 @@ func run() {
} else {
log.SetFormatter(&log.TextFormatter{FullTimestamp: true, DisableSorting: true})
}
log.Debugf("Global configuration loaded %+v", globalConfiguration)
jsonConf, _ := json.Marshal(globalConfiguration)
log.Debugf("Global configuration loaded %s", string(jsonConf))
server := NewServer(*globalConfiguration)
server.Start()
defer server.Close()
Expand Down
139 changes: 127 additions & 12 deletions configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
fmtlog "log"
"regexp"
"strings"
"time"

Expand All @@ -16,12 +17,12 @@ import (
// GlobalConfiguration holds global configuration (with providers, etc.).
// It's populated from the traefik configuration file passed as an argument to the binary.
type GlobalConfiguration struct {
Port string
GraceTimeOut int64
AccessLogsFile string
TraefikLogsFile string
Certificates Certificates
LogLevel string
EntryPoints EntryPoints
DefaultEntryPoints DefaultEntryPoints
ProvidersThrottleDuration time.Duration
MaxIdleConnsPerHost int
Docker *provider.Docker
Expand All @@ -34,6 +35,110 @@ type GlobalConfiguration struct {
Boltdb *provider.BoltDb
}

// DefaultEntryPoints holds default entry points
type DefaultEntryPoints []string

// String is the method to format the flag's value, part of the flag.Value interface.
// The String method's output will be used in diagnostics.
func (dep *DefaultEntryPoints) String() string {
return fmt.Sprintf("%#v", dep)
}

// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it.
func (dep *DefaultEntryPoints) Set(value string) error {
entrypoints := strings.Split(value, ",")
if len(entrypoints) == 0 {
return errors.New("Bad DefaultEntryPoints format: " + value)
}
for _, entrypoint := range entrypoints {
*dep = append(*dep, entrypoint)
}
return nil
}

// Type is type of the struct
func (dep *DefaultEntryPoints) Type() string {
return fmt.Sprint("defaultentrypoints²")
}

// EntryPoints holds entry points configuration of the reverse proxy (ip, port, TLS...)
type EntryPoints map[string]*EntryPoint

// String is the method to format the flag's value, part of the flag.Value interface.
// The String method's output will be used in diagnostics.
func (ep *EntryPoints) String() string {
return ""
}

// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it.
func (ep *EntryPoints) Set(value string) error {
regex := regexp.MustCompile("(?:Name:(?P<Name>\\S*))\\s*(?:Address:(?P<Address>\\S*))?\\s*(?:TLS:(?P<TLS>\\S*))?\\s*(?:Redirect.EntryPoint:(?P<RedirectEntryPoint>\\S*))?\\s*(?:Redirect.Regex:(?P<RedirectRegex>\\S*))?\\s*(?:Redirect.Replacement:(?P<RedirectReplacement>\\S*))?")
match := regex.FindAllStringSubmatch(value, -1)
if match == nil {
return errors.New("Bad EntryPoints format: " + value)
}
matchResult := match[0]
result := make(map[string]string)
for i, name := range regex.SubexpNames() {
if i != 0 {
result[name] = matchResult[i]
}
}
var tls *TLS
if len(result["TLS"]) > 0 {
certs := Certificates{}
certs.Set(result["TLS"])
tls = &TLS{
Certificates: certs,
}
}
var redirect *Redirect
if len(result["RedirectEntryPoint"]) > 0 || len(result["RedirectRegex"]) > 0 || len(result["RedirectReplacement"]) > 0 {
redirect = &Redirect{
EntryPoint: result["RedirectEntryPoint"],
Regex: result["RedirectRegex"],
Replacement: result["RedirectReplacement"],
}
}

(*ep)[result["Name"]] = &EntryPoint{
Address: result["Address"],
TLS: tls,
Redirect: redirect,
}

return nil
}

// Type is type of the struct
func (ep *EntryPoints) Type() string {
return fmt.Sprint("entrypoints²")
}

// EntryPoint holds an entry point configuration of the reverse proxy (ip, port, TLS...)
type EntryPoint struct {
Network string
Address string
TLS *TLS
Redirect *Redirect
}

// Redirect configures a redirection of an entry point to another, or to an URL
type Redirect struct {
EntryPoint string
Regex string
Replacement string
}

// TLS configures TLS for an entry point
type TLS struct {
Certificates Certificates
}

// Certificates defines traefik certificates type
type Certificates []Certificate

Expand Down Expand Up @@ -74,14 +179,7 @@ type Certificate struct {

// NewGlobalConfiguration returns a GlobalConfiguration with default values.
func NewGlobalConfiguration() *GlobalConfiguration {
globalConfiguration := new(GlobalConfiguration)
// default values
globalConfiguration.Port = ":80"
globalConfiguration.GraceTimeOut = 10
globalConfiguration.LogLevel = "ERROR"
globalConfiguration.ProvidersThrottleDuration = time.Duration(2 * time.Second)

return globalConfiguration
return new(GlobalConfiguration)
}

// LoadConfiguration returns a GlobalConfiguration.
Expand All @@ -101,8 +199,12 @@ func LoadConfiguration() *GlobalConfiguration {
if err := viper.ReadInConfig(); err != nil {
fmtlog.Fatalf("Error reading file: %s", err)
}
if len(arguments.Certificates) > 0 {
viper.Set("certificates", arguments.Certificates)

if len(arguments.EntryPoints) > 0 {
viper.Set("entryPoints", arguments.EntryPoints)
}
if len(arguments.DefaultEntryPoints) > 0 {
viper.Set("defaultEntryPoints", arguments.DefaultEntryPoints)
}
if arguments.web {
viper.Set("web", arguments.Web)
Expand Down Expand Up @@ -135,6 +237,19 @@ func LoadConfiguration() *GlobalConfiguration {
fmtlog.Fatalf("Error reading file: %s", err)
}

if len(configuration.EntryPoints) == 0 {
configuration.EntryPoints = make(map[string]*EntryPoint)
configuration.EntryPoints["http"] = &EntryPoint{
Address: ":80",
}
configuration.DefaultEntryPoints = []string{"http"}
}

if configuration.File != nil && len(configuration.File.Filename) == 0 {
// no filename, setting to global config file
configuration.File.Filename = viper.ConfigFileUsed()
}

return configuration
}

Expand Down
Binary file added docs/img/apollo-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/mantl-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 4ecb919

Please sign in to comment.