2015-11-01 21:29:47 +03:00
// Package provider holds the different provider implementation.
2015-11-01 18:35:01 +03:00
package provider
2015-10-01 13:04:25 +03:00
import (
2016-02-19 19:10:48 +03:00
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
2015-10-01 13:04:25 +03:00
"strings"
"text/template"
2015-11-01 18:35:01 +03:00
"time"
2015-10-01 13:04:25 +03:00
"github.com/BurntSushi/ty/fun"
log "github.com/Sirupsen/logrus"
2016-02-24 18:43:39 +03:00
"github.com/containous/traefik/types"
2015-11-01 18:35:01 +03:00
"github.com/docker/libkv"
2015-10-01 13:04:25 +03:00
"github.com/docker/libkv/store"
)
2015-11-01 21:29:47 +03:00
// Kv holds common configurations of key-value providers.
2015-11-02 21:48:34 +03:00
type Kv struct {
2016-01-14 00:46:44 +03:00
BaseProvider ` mapstructure:",squash" `
Endpoint string
Prefix string
2016-02-19 19:10:48 +03:00
TLS * KvTLS
2016-01-14 00:46:44 +03:00
storeType store . Backend
kvclient store . Store
2015-10-01 13:04:25 +03:00
}
2016-02-19 19:10:48 +03:00
// KvTLS holds TLS specific configurations
type KvTLS struct {
CA string
Cert string
Key string
InsecureSkipVerify bool
}
2016-03-05 01:52:08 +03:00
func ( provider * Kv ) watchKv ( configurationChan chan <- types . ConfigMessage , prefix string ) {
for {
chanKeys , err := provider . kvclient . WatchTree ( provider . Prefix , make ( chan struct { } ) /* stop chan */ )
if err != nil {
log . Errorf ( "Failed to WatchTree %s" , err )
continue
}
for range chanKeys {
configuration := provider . loadConfig ( )
if configuration != nil {
configurationChan <- types . ConfigMessage {
ProviderName : string ( provider . storeType ) ,
Configuration : configuration ,
}
}
}
log . Warnf ( "Intermittent failure to WatchTree KV. Retrying." )
}
}
2015-11-02 21:48:34 +03:00
func ( provider * Kv ) provide ( configurationChan chan <- types . ConfigMessage ) error {
2016-02-19 19:10:48 +03:00
storeConfig := & store . Config {
ConnectionTimeout : 30 * time . Second ,
Bucket : "traefik" ,
}
if provider . TLS != nil {
caPool := x509 . NewCertPool ( )
if provider . TLS . CA != "" {
ca , err := ioutil . ReadFile ( provider . TLS . CA )
if err != nil {
return fmt . Errorf ( "Failed to read CA. %s" , err )
}
caPool . AppendCertsFromPEM ( ca )
}
cert , err := tls . LoadX509KeyPair ( provider . TLS . Cert , provider . TLS . Key )
if err != nil {
return fmt . Errorf ( "Failed to load keypair. %s" , err )
}
storeConfig . TLS = & tls . Config {
Certificates : [ ] tls . Certificate { cert } ,
RootCAs : caPool ,
InsecureSkipVerify : provider . TLS . InsecureSkipVerify ,
}
}
2015-10-01 13:04:25 +03:00
kv , err := libkv . NewStore (
2016-01-14 00:46:44 +03:00
provider . storeType ,
2016-02-25 05:11:31 +03:00
strings . Split ( provider . Endpoint , "," ) ,
2016-02-19 19:10:48 +03:00
storeConfig ,
2015-10-01 13:04:25 +03:00
)
if err != nil {
return err
}
if _ , err := kv . List ( "" ) ; err != nil {
return err
}
provider . kvclient = kv
if provider . Watch {
2016-03-05 01:52:08 +03:00
go provider . watchKv ( configurationChan , provider . Prefix )
2015-10-01 13:04:25 +03:00
}
configuration := provider . loadConfig ( )
2015-11-13 13:50:32 +03:00
configurationChan <- types . ConfigMessage {
2016-01-14 00:46:44 +03:00
ProviderName : string ( provider . storeType ) ,
2015-11-13 13:50:32 +03:00
Configuration : configuration ,
}
2015-10-01 13:04:25 +03:00
return nil
}
2015-11-02 21:48:34 +03:00
func ( provider * Kv ) loadConfig ( ) * types . Configuration {
2015-10-01 13:04:25 +03:00
templateObjects := struct {
Prefix string
} {
2016-02-16 02:14:21 +03:00
// Allow `/traefik/alias` to superesede `provider.Prefix`
strings . TrimSuffix ( provider . get ( provider . Prefix , provider . Prefix + "/alias" ) , "/" ) ,
2015-10-01 13:04:25 +03:00
}
var KvFuncMap = template . FuncMap {
2016-02-01 18:08:58 +03:00
"List" : provider . list ,
"Get" : provider . get ,
"SplitGet" : provider . splitGet ,
"Last" : provider . last ,
2015-10-01 13:04:25 +03:00
}
2015-11-13 13:50:32 +03:00
configuration , err := provider . getConfiguration ( "templates/kv.tmpl" , KvFuncMap , templateObjects )
if err != nil {
log . Error ( err )
2015-10-01 13:04:25 +03:00
}
2015-11-13 13:50:32 +03:00
return configuration
}
2015-10-01 13:04:25 +03:00
2015-11-13 13:50:32 +03:00
func ( provider * Kv ) list ( keys ... string ) [ ] string {
joinedKeys := strings . Join ( keys , "" )
keysPairs , err := provider . kvclient . List ( joinedKeys )
2015-10-01 13:04:25 +03:00
if err != nil {
2016-02-01 18:08:58 +03:00
log . Errorf ( "Error getting keys %s %s " , joinedKeys , err )
2015-10-01 13:04:25 +03:00
return nil
}
2015-11-13 13:50:32 +03:00
directoryKeys := make ( map [ string ] string )
for _ , key := range keysPairs {
directory := strings . Split ( strings . TrimPrefix ( key . Key , strings . TrimPrefix ( joinedKeys , "/" ) ) , "/" ) [ 0 ]
directoryKeys [ directory ] = joinedKeys + directory
}
return fun . Values ( directoryKeys ) . ( [ ] string )
}
2015-10-01 13:04:25 +03:00
2016-02-01 18:08:58 +03:00
func ( provider * Kv ) get ( defaultValue string , keys ... string ) string {
2015-11-13 13:50:32 +03:00
joinedKeys := strings . Join ( keys , "" )
keyPair , err := provider . kvclient . Get ( joinedKeys )
if err != nil {
2016-02-01 18:08:58 +03:00
log . Warnf ( "Error getting key %s %s, setting default %s" , joinedKeys , err , defaultValue )
return defaultValue
2015-11-13 13:50:32 +03:00
} else if keyPair == nil {
2016-02-01 18:08:58 +03:00
log . Warnf ( "Error getting key %s, setting default %s" , joinedKeys , defaultValue )
return defaultValue
2015-10-01 13:04:25 +03:00
}
2015-11-13 13:50:32 +03:00
return string ( keyPair . Value )
}
2015-10-01 13:04:25 +03:00
2016-02-01 18:08:58 +03:00
func ( provider * Kv ) splitGet ( keys ... string ) [ ] string {
joinedKeys := strings . Join ( keys , "" )
keyPair , err := provider . kvclient . Get ( joinedKeys )
if err != nil {
log . Warnf ( "Error getting key %s %s, setting default empty" , joinedKeys , err )
return [ ] string { }
} else if keyPair == nil {
log . Warnf ( "Error getting key %s, setting default %empty" , joinedKeys )
return [ ] string { }
}
return strings . Split ( string ( keyPair . Value ) , "," )
}
2015-11-13 13:50:32 +03:00
func ( provider * Kv ) last ( key string ) string {
splittedKey := strings . Split ( key , "/" )
return splittedKey [ len ( splittedKey ) - 1 ]
2015-10-01 13:04:25 +03:00
}