traefik/traefik.go

280 lines
7.9 KiB
Go
Raw Normal View History

2015-09-11 14:37:13 +00:00
package main
import (
2016-07-28 18:41:25 +00:00
"crypto/tls"
2016-05-03 14:52:14 +00:00
"encoding/json"
"fmt"
fmtlog "log"
"net/http"
"os"
"reflect"
"runtime"
"strings"
"text/template"
"github.com/Sirupsen/logrus"
2016-05-03 14:52:14 +00:00
"github.com/containous/flaeg"
"github.com/containous/staert"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/log"
2016-05-03 14:52:14 +00:00
"github.com/containous/traefik/middlewares"
2016-05-18 13:45:48 +00:00
"github.com/containous/traefik/provider"
"github.com/containous/traefik/types"
"github.com/containous/traefik/version"
2016-06-24 07:58:42 +00:00
"github.com/docker/libkv/store"
"github.com/satori/go.uuid"
2015-09-11 23:55:10 +00:00
)
2015-09-11 14:37:13 +00:00
var versionTemplate = `Version: {{.Version}}
Codename: {{.Codename}}
Go version: {{.GoVersion}}
Built: {{.BuildTime}}
OS/Arch: {{.Os}}/{{.Arch}}`
2015-09-11 14:37:13 +00:00
func main() {
2015-09-25 22:20:45 +00:00
runtime.GOMAXPROCS(runtime.NumCPU())
2016-05-03 14:52:14 +00:00
//traefik config inits
traefikConfiguration := NewTraefikConfiguration()
traefikPointersConfiguration := NewTraefikDefaultPointersConfiguration()
2016-05-03 14:52:14 +00:00
//traefik Command init
traefikCmd := &flaeg.Command{
Name: "traefik",
Description: `traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
Complete documentation is available at https://traefik.io`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: func() error {
run(traefikConfiguration)
return nil
},
}
//version Command init
versionCmd := &flaeg.Command{
2016-05-24 12:58:25 +00:00
Name: "version",
Description: `Print version`,
Config: struct{}{},
DefaultPointersConfig: struct{}{},
2016-05-03 14:52:14 +00:00
Run: func() error {
tmpl, err := template.New("").Parse(versionTemplate)
if err != nil {
return err
}
v := struct {
Version string
Codename string
GoVersion string
BuildTime string
Os string
Arch string
}{
Version: version.Version,
Codename: version.Codename,
GoVersion: runtime.Version(),
BuildTime: version.BuildDate,
Os: runtime.GOOS,
Arch: runtime.GOARCH,
}
if err := tmpl.Execute(os.Stdout, v); err != nil {
return err
}
fmt.Printf("\n")
2016-05-03 14:52:14 +00:00
return nil
2016-05-03 14:52:14 +00:00
},
}
//storeconfig Command init
var kv *staert.KvSource
var err error
storeconfigCmd := &flaeg.Command{
Name: "storeconfig",
Description: `Store the static traefik configuration into a Key-value stores. Traefik will not start.`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: func() error {
if kv == nil {
return fmt.Errorf("Error using command storeconfig, no Key-value store defined")
}
jsonConf, _ := json.Marshal(traefikConfiguration.GlobalConfiguration)
fmtlog.Printf("Storing configuration: %s\n", jsonConf)
return kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
},
Metadata: map[string]string{
"parseAllSources": "true",
},
}
2016-05-03 14:52:14 +00:00
//init flaeg source
f := flaeg.New(traefikCmd, os.Args[1:])
//add custom parsers
f.AddParser(reflect.TypeOf(EntryPoints{}), &EntryPoints{})
f.AddParser(reflect.TypeOf(DefaultEntryPoints{}), &DefaultEntryPoints{})
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
2016-05-18 13:45:48 +00:00
f.AddParser(reflect.TypeOf(provider.Namespaces{}), &provider.Namespaces{})
f.AddParser(reflect.TypeOf([]acme.Domain{}), &acme.Domains{})
//add commands
2016-05-03 14:52:14 +00:00
f.AddCommand(versionCmd)
f.AddCommand(storeconfigCmd)
2016-07-29 15:36:53 +00:00
usedCmd, err := f.GetCommand()
if err != nil {
fmtlog.Println(err)
os.Exit(-1)
}
if _, err := f.Parse(usedCmd); err != nil {
2016-05-24 12:58:25 +00:00
fmtlog.Println(err)
os.Exit(-1)
}
//staert init
s := staert.NewStaert(traefikCmd)
//init toml source
toml := staert.NewTomlSource("traefik", []string{traefikConfiguration.ConfigFile, "/etc/traefik/", "$HOME/.traefik/", "."})
2016-05-03 14:52:14 +00:00
//add sources to staert
s.AddSource(toml)
s.AddSource(f)
2016-05-27 08:04:56 +00:00
if _, err := s.LoadConfig(); err != nil {
fmtlog.Println(fmt.Errorf("Error reading TOML config file %s : %s", toml.ConfigFileUsed(), err))
os.Exit(-1)
2016-05-24 12:58:25 +00:00
}
traefikConfiguration.ConfigFile = toml.ConfigFileUsed()
kv, err = CreateKvSource(traefikConfiguration)
2016-06-24 07:58:42 +00:00
if err != nil {
fmtlog.Println(err)
os.Exit(-1)
}
// IF a KV Store is enable and no sub-command called in args
if kv != nil && usedCmd == traefikCmd {
if traefikConfiguration.Cluster == nil {
traefikConfiguration.Cluster = &types.Cluster{Node: uuid.NewV4().String()}
}
if traefikConfiguration.Cluster.Store == nil {
traefikConfiguration.Cluster.Store = &types.Store{Prefix: kv.Prefix, Store: kv.Store}
}
2016-06-24 07:58:42 +00:00
s.AddSource(kv)
if _, err := s.LoadConfig(); err != nil {
2016-07-07 15:25:42 +00:00
fmtlog.Println(err)
os.Exit(-1)
2016-06-24 07:58:42 +00:00
}
}
2016-05-03 14:52:14 +00:00
if err := s.Run(); err != nil {
2016-01-13 21:46:44 +00:00
fmtlog.Println(err)
os.Exit(-1)
2015-11-23 14:41:16 +00:00
}
2016-05-03 14:52:14 +00:00
2016-01-13 21:46:44 +00:00
os.Exit(0)
2015-09-11 14:37:13 +00:00
}
2016-05-03 14:52:14 +00:00
func run(traefikConfiguration *TraefikConfiguration) {
fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags)
// load global configuration
globalConfiguration := traefikConfiguration.GlobalConfiguration
http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = globalConfiguration.MaxIdleConnsPerHost
if globalConfiguration.InsecureSkipVerify {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
2016-05-03 14:52:14 +00:00
loggerMiddleware := middlewares.NewLogger(globalConfiguration.AccessLogsFile)
defer loggerMiddleware.Close()
if globalConfiguration.File != nil && len(globalConfiguration.File.Filename) == 0 {
// no filename, setting to global config file
if len(traefikConfiguration.ConfigFile) != 0 {
globalConfiguration.File.Filename = traefikConfiguration.ConfigFile
} else {
log.Errorln("Error using file configuration backend, no filename defined")
}
}
if len(globalConfiguration.EntryPoints) == 0 {
globalConfiguration.EntryPoints = map[string]*EntryPoint{"http": {Address: ":80"}}
globalConfiguration.DefaultEntryPoints = []string{"http"}
}
if globalConfiguration.Debug {
globalConfiguration.LogLevel = "DEBUG"
}
// logging
level, err := logrus.ParseLevel(strings.ToLower(globalConfiguration.LogLevel))
if err != nil {
2016-08-19 08:36:54 +00:00
log.Error("Error getting level", err)
}
log.SetLevel(level)
2016-05-03 14:52:14 +00:00
if len(globalConfiguration.TraefikLogsFile) > 0 {
fi, err := os.OpenFile(globalConfiguration.TraefikLogsFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
defer func() {
if err := fi.Close(); err != nil {
log.Error("Error closing file", err)
2016-05-03 14:52:14 +00:00
}
}()
if err != nil {
2016-08-19 08:36:54 +00:00
log.Error("Error opening file", err)
2016-05-03 14:52:14 +00:00
} else {
log.SetOutput(fi)
log.SetFormatter(&logrus.TextFormatter{DisableColors: true, FullTimestamp: true, DisableSorting: true})
2016-05-03 14:52:14 +00:00
}
} else {
log.SetFormatter(&logrus.TextFormatter{FullTimestamp: true, DisableSorting: true})
2016-05-03 14:52:14 +00:00
}
jsonConf, _ := json.Marshal(globalConfiguration)
log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
if len(traefikConfiguration.ConfigFile) != 0 {
log.Infof("Using TOML configuration file %s", traefikConfiguration.ConfigFile)
}
2016-05-03 14:52:14 +00:00
log.Debugf("Global configuration loaded %s", string(jsonConf))
server := NewServer(globalConfiguration)
server.Start()
defer server.Close()
log.Info("Shutting down")
}
// CreateKvSource creates KvSource
// TLS support is enable for Consul and Etcd backends
func CreateKvSource(traefikConfiguration *TraefikConfiguration) (*staert.KvSource, error) {
var kv *staert.KvSource
var store store.Store
var err error
switch {
case traefikConfiguration.Consul != nil:
store, err = traefikConfiguration.Consul.CreateStore()
kv = &staert.KvSource{
Store: store,
Prefix: traefikConfiguration.Consul.Prefix,
}
case traefikConfiguration.Etcd != nil:
store, err = traefikConfiguration.Etcd.CreateStore()
kv = &staert.KvSource{
Store: store,
Prefix: traefikConfiguration.Etcd.Prefix,
}
case traefikConfiguration.Zookeeper != nil:
store, err = traefikConfiguration.Zookeeper.CreateStore()
kv = &staert.KvSource{
Store: store,
Prefix: traefikConfiguration.Zookeeper.Prefix,
}
case traefikConfiguration.Boltdb != nil:
store, err = traefikConfiguration.Boltdb.CreateStore()
kv = &staert.KvSource{
Store: store,
Prefix: traefikConfiguration.Boltdb.Prefix,
}
}
return kv, err
}