2015-11-01 19:29:47 +01:00
// Package provider holds the different provider implementation.
2015-11-01 16:35:01 +01:00
package provider
2015-10-01 12:04:25 +02:00
import (
2016-02-19 17:10:48 +01:00
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
2015-10-01 12:04:25 +02:00
"strings"
"text/template"
2015-11-01 16:35:01 +01:00
"time"
2015-10-01 12:04:25 +02:00
2016-04-19 22:06:33 +02:00
"errors"
2015-10-01 12:04:25 +02:00
"github.com/BurntSushi/ty/fun"
log "github.com/Sirupsen/logrus"
2016-04-19 22:06:33 +02:00
"github.com/cenkalti/backoff"
2016-03-31 18:57:08 +02:00
"github.com/containous/traefik/safe"
2016-02-24 16:43:39 +01:00
"github.com/containous/traefik/types"
2015-11-01 16:35:01 +01:00
"github.com/docker/libkv"
2015-10-01 12:04:25 +02:00
"github.com/docker/libkv/store"
)
2015-11-01 19:29:47 +01:00
// Kv holds common configurations of key-value providers.
2015-11-02 19:48:34 +01:00
type Kv struct {
2016-01-13 22:46:44 +01:00
BaseProvider ` mapstructure:",squash" `
Endpoint string
Prefix string
2016-02-19 17:10:48 +01:00
TLS * KvTLS
2016-01-13 22:46:44 +01:00
storeType store . Backend
kvclient store . Store
2015-10-01 12:04:25 +02:00
}
2016-02-19 17:10:48 +01:00
// KvTLS holds TLS specific configurations
type KvTLS struct {
CA string
Cert string
Key string
InsecureSkipVerify bool
}
2016-04-28 01:43:43 +02:00
func ( provider * Kv ) watchKv ( configurationChan chan <- types . ConfigMessage , prefix string , stop chan bool ) error {
2016-04-19 22:06:33 +02:00
operation := func ( ) error {
2016-04-28 01:43:43 +02:00
events , err := provider . kvclient . WatchTree ( provider . Prefix , make ( chan struct { } ) )
2016-03-04 22:52:08 +00:00
if err != nil {
2016-04-28 01:43:43 +02:00
return fmt . Errorf ( "Failed to KV WatchTree: %v" , err )
2016-03-04 22:52:08 +00:00
}
2016-04-19 22:06:33 +02:00
for {
select {
case <- stop :
return nil
case _ , ok := <- events :
if ! ok {
return errors . New ( "watchtree channel closed" )
}
configuration := provider . loadConfig ( )
if configuration != nil {
configurationChan <- types . ConfigMessage {
ProviderName : string ( provider . storeType ) ,
Configuration : configuration ,
}
2016-03-04 22:52:08 +00:00
}
}
}
}
2016-04-19 22:06:33 +02:00
notify := func ( err error , time time . Duration ) {
2016-04-28 01:43:43 +02:00
log . Errorf ( "KV connection error: %+v, retrying in %s" , err , time )
2016-04-19 22:06:33 +02:00
}
err := backoff . RetryNotify ( operation , backoff . NewExponentialBackOff ( ) , notify )
if err != nil {
2016-04-28 01:43:43 +02:00
return fmt . Errorf ( "Cannot connect to KV server: %v" , err )
2016-04-19 22:06:33 +02:00
}
2016-04-28 01:43:43 +02:00
return nil
2016-03-04 22:52:08 +00:00
}
2016-04-13 20:36:23 +02:00
func ( provider * Kv ) provide ( configurationChan chan <- types . ConfigMessage , pool * safe . Pool ) error {
2016-02-19 17:10:48 +01: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 ,
}
}
2016-04-19 22:06:33 +02:00
operation := func ( ) error {
kv , err := libkv . NewStore (
provider . storeType ,
strings . Split ( provider . Endpoint , "," ) ,
storeConfig ,
)
if err != nil {
2016-04-28 01:43:43 +02:00
return fmt . Errorf ( "Failed to Connect to KV store: %v" , err )
2016-04-19 22:06:33 +02:00
}
2016-04-28 01:43:43 +02:00
if _ , err := kv . Exists ( "qmslkjdfmqlskdjfmqlksjazçueznbvbwzlkajzebvkwjdcqmlsfj" ) ; err != nil {
return fmt . Errorf ( "Failed to test KV store connection: %v" , err )
2016-04-19 22:06:33 +02:00
}
provider . kvclient = kv
if provider . Watch {
pool . Go ( func ( stop chan bool ) {
2016-04-28 01:43:43 +02:00
err := provider . watchKv ( configurationChan , provider . Prefix , stop )
if err != nil {
log . Errorf ( "Cannot watch KV store: %v" , err )
}
2016-04-19 22:06:33 +02:00
} )
}
configuration := provider . loadConfig ( )
configurationChan <- types . ConfigMessage {
ProviderName : string ( provider . storeType ) ,
Configuration : configuration ,
}
return nil
2015-10-01 12:04:25 +02:00
}
2016-04-19 22:06:33 +02:00
notify := func ( err error , time time . Duration ) {
2016-04-28 01:43:43 +02:00
log . Errorf ( "KV connection error: %+v, retrying in %s" , err , time )
2015-10-01 12:04:25 +02:00
}
2016-04-19 22:06:33 +02:00
err := backoff . RetryNotify ( operation , backoff . NewExponentialBackOff ( ) , notify )
if err != nil {
2016-04-28 01:43:43 +02:00
return fmt . Errorf ( "Cannot connect to KV server: %v" , err )
2015-11-13 11:50:32 +01:00
}
2015-10-01 12:04:25 +02:00
return nil
}
2015-11-02 19:48:34 +01:00
func ( provider * Kv ) loadConfig ( ) * types . Configuration {
2015-10-01 12:04:25 +02:00
templateObjects := struct {
Prefix string
} {
2016-02-15 18:14:21 -05:00
// Allow `/traefik/alias` to superesede `provider.Prefix`
strings . TrimSuffix ( provider . get ( provider . Prefix , provider . Prefix + "/alias" ) , "/" ) ,
2015-10-01 12:04:25 +02:00
}
var KvFuncMap = template . FuncMap {
2016-02-01 16:08:58 +01:00
"List" : provider . list ,
"Get" : provider . get ,
"SplitGet" : provider . splitGet ,
"Last" : provider . last ,
2015-10-01 12:04:25 +02:00
}
2015-11-13 11:50:32 +01:00
configuration , err := provider . getConfiguration ( "templates/kv.tmpl" , KvFuncMap , templateObjects )
if err != nil {
log . Error ( err )
2015-10-01 12:04:25 +02:00
}
2015-11-13 11:50:32 +01:00
return configuration
}
2015-10-01 12:04:25 +02:00
2015-11-13 11:50:32 +01:00
func ( provider * Kv ) list ( keys ... string ) [ ] string {
joinedKeys := strings . Join ( keys , "" )
keysPairs , err := provider . kvclient . List ( joinedKeys )
2015-10-01 12:04:25 +02:00
if err != nil {
2016-02-01 16:08:58 +01:00
log . Errorf ( "Error getting keys %s %s " , joinedKeys , err )
2015-10-01 12:04:25 +02:00
return nil
}
2015-11-13 11:50:32 +01:00
directoryKeys := make ( map [ string ] string )
for _ , key := range keysPairs {
2016-04-27 22:28:02 +02:00
directory := strings . Split ( strings . TrimPrefix ( key . Key , joinedKeys ) , "/" ) [ 0 ]
2015-11-13 11:50:32 +01:00
directoryKeys [ directory ] = joinedKeys + directory
}
return fun . Values ( directoryKeys ) . ( [ ] string )
}
2015-10-01 12:04:25 +02:00
2016-02-01 16:08:58 +01:00
func ( provider * Kv ) get ( defaultValue string , keys ... string ) string {
2015-11-13 11:50:32 +01:00
joinedKeys := strings . Join ( keys , "" )
2016-04-27 22:28:02 +02:00
keyPair , err := provider . kvclient . Get ( strings . TrimPrefix ( joinedKeys , "/" ) )
2015-11-13 11:50:32 +01:00
if err != nil {
2016-02-01 16:08:58 +01:00
log . Warnf ( "Error getting key %s %s, setting default %s" , joinedKeys , err , defaultValue )
return defaultValue
2015-11-13 11:50:32 +01:00
} else if keyPair == nil {
2016-02-01 16:08:58 +01:00
log . Warnf ( "Error getting key %s, setting default %s" , joinedKeys , defaultValue )
return defaultValue
2015-10-01 12:04:25 +02:00
}
2015-11-13 11:50:32 +01:00
return string ( keyPair . Value )
}
2015-10-01 12:04:25 +02:00
2016-02-01 16:08:58 +01: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 11:50:32 +01:00
func ( provider * Kv ) last ( key string ) string {
splittedKey := strings . Split ( key , "/" )
return splittedKey [ len ( splittedKey ) - 1 ]
2015-10-01 12:04:25 +02:00
}