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
"fmt"
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-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"
2016-08-19 14:24:09 +02:00
"github.com/emilevauge/backoff"
2015-10-01 12:04:25 +02:00
)
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-06-24 09:58:42 +02:00
BaseProvider ` mapstructure:",squash" `
2016-06-27 16:14:56 +02:00
Endpoint string ` description:"Comma sepparated server endpoints" `
Prefix string ` description:"Prefix used for KV store" `
TLS * ClientTLS ` description:"Enable TLS support" `
2016-06-24 09:58:42 +02:00
storeType store . Backend
kvclient store . Store
2015-10-01 12:04:25 +02:00
}
2016-07-13 17:18:55 +02:00
func ( provider * Kv ) createStore ( ) ( store . Store , error ) {
storeConfig := & store . Config {
ConnectionTimeout : 30 * time . Second ,
Bucket : "traefik" ,
}
if provider . TLS != nil {
var err error
storeConfig . TLS , err = provider . TLS . CreateTLSConfig ( )
if err != nil {
return nil , err
}
}
return libkv . NewStore (
provider . storeType ,
strings . Split ( provider . Endpoint , "," ) ,
storeConfig ,
)
}
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
}
2016-08-19 14:24:09 +02:00
err := backoff . RetryNotify ( operation , backoff . NewJobBackOff ( backoff . NewExponentialBackOff ( ) ) , notify )
2016-04-19 22:06:33 +02:00
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-05-31 09:54:42 +02:00
func ( provider * Kv ) provide ( configurationChan chan <- types . ConfigMessage , pool * safe . Pool , constraints [ ] types . Constraint ) error {
2016-04-19 22:06:33 +02:00
operation := func ( ) error {
2016-07-13 17:18:55 +02:00
if _ , err := provider . kvclient . Exists ( "qmslkjdfmqlskdjfmqlksjazçueznbvbwzlkajzebvkwjdcqmlsfj" ) ; err != nil {
2016-04-28 01:43:43 +02:00
return fmt . Errorf ( "Failed to test KV store connection: %v" , err )
2016-04-19 22:06:33 +02:00
}
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-08-19 14:24:09 +02:00
err := backoff . RetryNotify ( operation , backoff . NewJobBackOff ( backoff . NewExponentialBackOff ( ) ) , notify )
2016-04-19 22:06:33 +02:00
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
}