2015-09-07 11:38:58 +03:00
package main
2015-09-25 12:44:19 +03:00
import (
2016-01-23 19:41:56 +03:00
"errors"
"fmt"
2015-11-06 20:11:57 +03:00
fmtlog "log"
2016-02-01 18:08:58 +03:00
"regexp"
2016-01-23 19:41:56 +03:00
"strings"
2015-10-08 18:56:45 +03:00
"time"
2015-11-01 18:35:01 +03:00
2016-02-24 18:43:39 +03:00
"github.com/containous/traefik/provider"
"github.com/containous/traefik/types"
2016-01-14 00:46:44 +03:00
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
2016-02-25 20:30:13 +03:00
"sync"
2015-09-25 12:44:19 +03:00
)
2015-11-06 20:11:57 +03:00
// GlobalConfiguration holds global configuration (with providers, etc.).
// It's populated from the traefik configuration file passed as an argument to the binary.
2015-09-10 16:13:35 +03:00
type GlobalConfiguration struct {
2015-10-17 15:14:20 +03:00
GraceTimeOut int64
AccessLogsFile string
TraefikLogsFile string
LogLevel string
2016-01-29 22:34:17 +03:00
EntryPoints EntryPoints
2016-02-25 20:30:13 +03:00
ACME * ACME
2016-01-29 22:34:17 +03:00
DefaultEntryPoints DefaultEntryPoints
2015-10-17 15:14:20 +03:00
ProvidersThrottleDuration time . Duration
2016-02-10 00:29:01 +03:00
MaxIdleConnsPerHost int
2015-11-02 21:48:34 +03:00
Docker * provider . Docker
File * provider . File
2015-10-17 15:14:20 +03:00
Web * WebProvider
2015-11-02 21:48:34 +03:00
Marathon * provider . Marathon
Consul * provider . Consul
2016-02-02 20:03:40 +03:00
ConsulCatalog * provider . ConsulCatalog
2015-11-02 21:48:34 +03:00
Etcd * provider . Etcd
Zookeeper * provider . Zookepper
Boltdb * provider . BoltDb
2015-09-10 16:13:35 +03:00
}
2016-01-29 22:34:17 +03:00
// 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
}
2016-02-25 20:30:13 +03:00
// ACME allows to connect to lets encrypt and retrieve certs
type ACME struct {
Email string
Domains [ ] Domain
StorageFile string
OnDemand bool
CAServer string
EntryPoint string
storageLock sync . Mutex
}
// Domain holds a domain name with SANs
type Domain struct {
Main string
SANs [ ] string
}
2016-01-14 00:46:44 +03:00
// Certificates defines traefik certificates type
type Certificates [ ] Certificate
// 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 ( certs * Certificates ) String ( ) string {
if len ( * certs ) == 0 {
return ""
}
return ( * certs ) [ 0 ] . CertFile + "," + ( * certs ) [ 0 ] . KeyFile
}
// 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 ( certs * Certificates ) Set ( value string ) error {
files := strings . Split ( value , "," )
if len ( files ) != 2 {
return errors . New ( "Bad certificates format: " + value )
}
* certs = append ( * certs , Certificate {
CertFile : files [ 0 ] ,
KeyFile : files [ 1 ] ,
} )
return nil
}
// Type is type of the struct
func ( certs * Certificates ) Type ( ) string {
return fmt . Sprint ( "certificates" )
}
2015-11-21 04:59:49 +03:00
// Certificate holds a SSL cert/key pair
type Certificate struct {
CertFile string
KeyFile string
}
2015-11-06 20:11:57 +03:00
// NewGlobalConfiguration returns a GlobalConfiguration with default values.
2015-09-10 16:13:35 +03:00
func NewGlobalConfiguration ( ) * GlobalConfiguration {
2016-01-29 22:34:17 +03:00
return new ( GlobalConfiguration )
2015-09-10 16:13:35 +03:00
}
2015-09-07 11:38:58 +03:00
2016-01-14 00:46:44 +03:00
// LoadConfiguration returns a GlobalConfiguration.
func LoadConfiguration ( ) * GlobalConfiguration {
2015-11-06 20:11:57 +03:00
configuration := NewGlobalConfiguration ( )
2016-01-14 00:46:44 +03:00
viper . SetEnvPrefix ( "traefik" )
viper . SetConfigType ( "toml" )
viper . AutomaticEnv ( )
if len ( viper . GetString ( "configFile" ) ) > 0 {
viper . SetConfigFile ( viper . GetString ( "configFile" ) )
} else {
viper . SetConfigName ( "traefik" ) // name of config file (without extension)
}
2016-01-22 14:36:24 +03:00
viper . AddConfigPath ( "/etc/traefik/" ) // path to look for the config file in
viper . AddConfigPath ( "$HOME/.traefik/" ) // call multiple times to add many search paths
viper . AddConfigPath ( "." ) // optionally look for config in the working directory
2016-01-23 19:41:56 +03:00
if err := viper . ReadInConfig ( ) ; err != nil {
2016-01-14 00:46:44 +03:00
fmtlog . Fatalf ( "Error reading file: %s" , err )
}
2016-01-29 22:34:17 +03:00
if len ( arguments . EntryPoints ) > 0 {
viper . Set ( "entryPoints" , arguments . EntryPoints )
}
if len ( arguments . DefaultEntryPoints ) > 0 {
viper . Set ( "defaultEntryPoints" , arguments . DefaultEntryPoints )
2016-01-14 00:46:44 +03:00
}
if arguments . web {
viper . Set ( "web" , arguments . Web )
}
if arguments . file {
viper . Set ( "file" , arguments . File )
}
if ! arguments . dockerTLS {
arguments . Docker . TLS = nil
}
if arguments . docker {
viper . Set ( "docker" , arguments . Docker )
}
if arguments . marathon {
viper . Set ( "marathon" , arguments . Marathon )
}
2016-02-19 19:10:48 +03:00
if ! arguments . consulTLS {
arguments . Consul . TLS = nil
}
2016-01-14 00:46:44 +03:00
if arguments . consul {
viper . Set ( "consul" , arguments . Consul )
}
2016-02-02 20:03:40 +03:00
if arguments . consulCatalog {
viper . Set ( "consulCatalog" , arguments . ConsulCatalog )
}
2016-01-14 00:46:44 +03:00
if arguments . zookeeper {
viper . Set ( "zookeeper" , arguments . Zookeeper )
}
2016-02-19 19:10:48 +03:00
if ! arguments . etcdTLS {
arguments . Etcd . TLS = nil
}
2016-01-14 00:46:44 +03:00
if arguments . etcd {
viper . Set ( "etcd" , arguments . Etcd )
}
if arguments . boltdb {
viper . Set ( "boltdb" , arguments . Boltdb )
}
2016-01-23 19:41:56 +03:00
if err := unmarshal ( & configuration ) ; err != nil {
2016-02-25 20:30:13 +03:00
2015-11-06 20:11:57 +03:00
fmtlog . Fatalf ( "Error reading file: %s" , err )
}
2016-01-14 00:46:44 +03:00
2016-01-29 22:34:17 +03:00
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 ( )
}
2015-11-06 20:11:57 +03:00
return configuration
}
2016-01-14 00:46:44 +03:00
func unmarshal ( rawVal interface { } ) error {
config := & mapstructure . DecoderConfig {
DecodeHook : mapstructure . StringToTimeDurationHookFunc ( ) ,
Metadata : nil ,
Result : rawVal ,
WeaklyTypedInput : true ,
}
decoder , err := mapstructure . NewDecoder ( config )
if err != nil {
return err
}
err = decoder . Decode ( viper . AllSettings ( ) )
if err != nil {
return err
}
return nil
}
2015-11-01 18:35:01 +03:00
type configs map [ string ] * types . Configuration