2015-09-11 14:37:13 +00:00
package main
import (
2016-05-03 14:52:14 +00:00
"encoding/json"
2016-06-02 13:17:04 +00:00
"fmt"
2016-05-03 14:52:14 +00:00
log "github.com/Sirupsen/logrus"
"github.com/containous/flaeg"
"github.com/containous/staert"
2016-05-25 15:06:34 +00:00
"github.com/containous/traefik/acme"
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"
2016-05-31 07:54:42 +00:00
"github.com/containous/traefik/types"
2016-06-24 07:58:42 +00:00
"github.com/docker/libkv/store"
"github.com/docker/libkv/store/boltdb"
"github.com/docker/libkv/store/consul"
"github.com/docker/libkv/store/etcd"
"github.com/docker/libkv/store/zookeeper"
2015-09-24 15:16:13 +00:00
fmtlog "log"
2016-05-03 14:52:14 +00:00
"net/http"
2015-09-24 15:16:13 +00:00
"os"
2016-05-03 14:52:14 +00:00
"reflect"
2015-11-01 15:35:01 +00:00
"runtime"
2016-05-03 14:52:14 +00:00
"strings"
2016-06-02 13:17:04 +00:00
"text/template"
2015-09-11 23:55:10 +00:00
)
2015-09-11 14:37:13 +00:00
2016-06-02 13:17:04 +00:00
var versionTemplate = ` Version : { { . Version } }
2016-07-05 19:03:37 +00:00
Codename : { { . Codename } }
2016-06-02 13:17:04 +00:00
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 ( )
2016-05-25 15:06:34 +00:00
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 {
2016-06-02 13:17:04 +00:00
tmpl , err := template . New ( "" ) . Parse ( versionTemplate )
if err != nil {
return err
}
v := struct {
Version string
2016-07-05 19:03:37 +00:00
Codename string
2016-06-02 13:17:04 +00:00
GoVersion string
BuildTime string
Os string
Arch string
} {
Version : Version ,
2016-07-05 19:03:37 +00:00
Codename : Codename ,
2016-06-02 13:17:04 +00:00
GoVersion : runtime . Version ( ) ,
BuildTime : 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-06-02 13:17:04 +00:00
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 { } )
2016-06-02 13:17:04 +00:00
f . AddParser ( reflect . TypeOf ( types . Constraints { } ) , & types . Constraints { } )
2016-05-18 13:45:48 +00:00
f . AddParser ( reflect . TypeOf ( provider . Namespaces { } ) , & provider . Namespaces { } )
2016-05-25 15:06:34 +00:00
f . AddParser ( reflect . TypeOf ( [ ] acme . Domain { } ) , & acme . Domains { } )
2016-05-03 14:52:14 +00:00
//add version command
f . AddCommand ( versionCmd )
2016-05-24 12:58:25 +00:00
if _ , err := f . Parse ( traefikCmd ) ; err != nil {
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 {
2016-06-03 15:58:33 +00:00
fmtlog . Println ( fmt . Errorf ( "Error reading TOML config file %s : %s" , toml . ConfigFileUsed ( ) , err ) )
2016-05-24 12:58:25 +00:00
}
2016-05-30 09:37:12 +00:00
traefikConfiguration . ConfigFile = toml . ConfigFileUsed ( )
2016-06-24 07:58:42 +00:00
var kv * staert . KvSource
var err error
if traefikConfiguration . Consul != nil {
//init KvSource
consul . Register ( )
kv , err = staert . NewKvSource (
store . CONSUL ,
strings . Split ( traefikConfiguration . Consul . Endpoint , "," ) ,
nil ,
strings . TrimPrefix ( traefikConfiguration . Consul . Prefix , "/" ) , // TrimPrefix should be done in https://github.com/docker/libkv/blob/master/store/consul/consul.go#L113 : IDK why it doen't work
)
} else if traefikConfiguration . Etcd != nil {
//init KvSource
etcd . Register ( )
kv , err = staert . NewKvSource (
store . ETCD ,
strings . Split ( traefikConfiguration . Etcd . Endpoint , "," ) ,
nil ,
traefikConfiguration . Etcd . Prefix ,
)
} else if traefikConfiguration . Zookeeper != nil {
//init KvSource
zookeeper . Register ( )
kv , err = staert . NewKvSource (
store . ZK ,
strings . Split ( traefikConfiguration . Zookeeper . Endpoint , "," ) ,
nil ,
traefikConfiguration . Zookeeper . Prefix ,
)
} else if traefikConfiguration . Boltdb != nil {
//init KvSource
boltdb . Register ( )
kv , err = staert . NewKvSource (
store . BOLTDB ,
strings . Split ( traefikConfiguration . Boltdb . Endpoint , "," ) ,
nil ,
traefikConfiguration . Boltdb . Prefix ,
)
}
if err != nil {
fmtlog . Println ( err )
os . Exit ( - 1 )
}
// TO DELETE : Used once to fill the kv store
// if kv != nil {
// fmtlog.Println("Try to store global configuration in consul store")
// if err := kv.StoreConfig(traefikConfiguration); err != nil {
// fmtlog.Println(fmt.Errorf("Error : %s", err))
// os.Exit(-1)
// } else {
// fmtlog.Println("It seems okay :)")
// jsonConf, _ := json.Marshal(traefikConfiguration)
// fmtlog.Printf("Global configuration loaded %s", string(jsonConf))
// os.Exit(0)
// }
// }
//TODO : log warning if many KvStore or set priority
if kv != nil {
fmtlog . Println ( "KV Store found" )
s . AddSource ( kv )
if _ , err := s . LoadConfig ( ) ; err != nil {
fmtlog . Println ( fmt . Errorf ( "Error : %s" , err ) )
}
}
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
loggerMiddleware := middlewares . NewLogger ( globalConfiguration . AccessLogsFile )
defer loggerMiddleware . Close ( )
2016-06-02 09:37:51 +00:00
if globalConfiguration . File != nil && len ( globalConfiguration . File . Filename ) == 0 {
2016-05-30 09:37:12 +00:00
// no filename, setting to global config file
if len ( traefikConfiguration . ConfigFile ) != 0 {
2016-06-02 09:37:51 +00:00
globalConfiguration . File . Filename = traefikConfiguration . ConfigFile
2016-05-30 09:37:12 +00:00
} else {
log . Errorln ( "Error using file configuration backend, no filename defined" )
}
}
2016-06-02 09:37:51 +00:00
if len ( globalConfiguration . EntryPoints ) == 0 {
globalConfiguration . EntryPoints = map [ string ] * EntryPoint { "http" : { Address : ":80" } }
globalConfiguration . DefaultEntryPoints = [ ] string { "http" }
2016-05-30 09:37:12 +00:00
}
2016-06-02 13:17:04 +00:00
if globalConfiguration . Debug {
globalConfiguration . LogLevel = "DEBUG"
}
2016-06-02 09:37:51 +00:00
// logging
level , err := log . ParseLevel ( strings . ToLower ( globalConfiguration . LogLevel ) )
if err != nil {
log . Fatal ( "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 closinf file" , err )
}
} ( )
if err != nil {
log . Fatal ( "Error opening file" , err )
} else {
log . SetOutput ( fi )
log . SetFormatter ( & log . TextFormatter { DisableColors : true , FullTimestamp : true , DisableSorting : true } )
}
} else {
log . SetFormatter ( & log . TextFormatter { FullTimestamp : true , DisableSorting : true } )
}
jsonConf , _ := json . Marshal ( globalConfiguration )
2016-05-24 13:45:20 +00:00
log . Infof ( "Traefik version %s built on %s" , Version , BuildDate )
2016-05-30 15:57:57 +00:00
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" )
}