2019-11-28 20:56:04 +00:00
package consul
import (
2022-09-12 15:40:09 +00:00
"context"
2022-01-12 13:42:21 +00:00
"errors"
2022-09-12 15:40:09 +00:00
"fmt"
"time"
2022-01-12 13:42:21 +00:00
2022-09-12 15:40:09 +00:00
"github.com/kvtools/consul"
2022-11-21 17:36:05 +00:00
"github.com/rs/zerolog/log"
2020-09-16 13:46:04 +00:00
"github.com/traefik/traefik/v2/pkg/provider"
"github.com/traefik/traefik/v2/pkg/provider/kv"
2022-09-12 15:40:09 +00:00
"github.com/traefik/traefik/v2/pkg/types"
2019-11-28 20:56:04 +00:00
)
2022-06-03 10:00:09 +00:00
// providerName is the Consul provider name.
const providerName = "consul"
2019-11-28 20:56:04 +00:00
var _ provider . Provider = ( * Provider ) ( nil )
2022-06-03 10:00:09 +00:00
// ProviderBuilder is responsible for constructing namespaced instances of the Consul provider.
type ProviderBuilder struct {
2022-07-12 10:12:08 +00:00
kv . Provider ` yaml:",inline" export:"true" `
2022-06-03 10:00:09 +00:00
2022-09-12 15:40:09 +00:00
Token string ` description:"Per-request ACL token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false" `
TLS * types . ClientTLS ` description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true" `
2022-06-03 10:00:09 +00:00
// Deprecated: use Namespaces instead.
Namespace string ` description:"Sets the namespace used to discover the configuration (Consul Enterprise only)." json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty" `
Namespaces [ ] string ` description:"Sets the namespaces used to discover the configuration (Consul Enterprise only)." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" `
2019-11-28 20:56:04 +00:00
}
// SetDefaults sets the default values.
2022-06-03 10:00:09 +00:00
func ( p * ProviderBuilder ) SetDefaults ( ) {
2019-11-28 20:56:04 +00:00
p . Provider . SetDefaults ( )
p . Endpoints = [ ] string { "127.0.0.1:8500" }
}
2022-06-03 10:00:09 +00:00
// BuildProviders builds Consul provider instances for the given namespaces configuration.
func ( p * ProviderBuilder ) BuildProviders ( ) [ ] * Provider {
// We can warn about that, because we've already made sure before that
// Namespace and Namespaces are mutually exclusive.
if p . Namespace != "" {
2022-11-21 17:36:05 +00:00
log . Warn ( ) . Msg ( "Namespace option is deprecated, please use the Namespaces option instead." )
2022-06-03 10:00:09 +00:00
}
if len ( p . Namespaces ) == 0 {
return [ ] * Provider { {
Provider : p . Provider ,
name : providerName ,
// p.Namespace could very well be empty.
namespace : p . Namespace ,
2022-09-12 15:40:09 +00:00
token : p . Token ,
tls : p . TLS ,
2022-06-03 10:00:09 +00:00
} }
}
var providers [ ] * Provider
for _ , namespace := range p . Namespaces {
providers = append ( providers , & Provider {
Provider : p . Provider ,
name : providerName + "-" + namespace ,
namespace : namespace ,
2022-09-12 15:40:09 +00:00
token : p . Token ,
tls : p . TLS ,
2022-06-03 10:00:09 +00:00
} )
}
return providers
}
// Provider holds configurations of the provider.
type Provider struct {
kv . Provider
name string
namespace string
2022-09-12 15:40:09 +00:00
token string
tls * types . ClientTLS
2022-06-03 10:00:09 +00:00
}
2020-05-11 10:06:07 +00:00
// Init the provider.
2019-11-28 20:56:04 +00:00
func ( p * Provider ) Init ( ) error {
2022-01-12 13:42:21 +00:00
// Wildcard namespace allows fetching KV values from any namespace for recursive requests (see https://www.consul.io/api/kv#ns).
// As we are not supporting multiple namespaces at the same time, wildcard namespace is not allowed.
2022-06-03 10:00:09 +00:00
if p . namespace == "*" {
2022-01-12 13:42:21 +00:00
return errors . New ( "wildcard namespace is not supported" )
}
2022-06-03 10:00:09 +00:00
// In case they didn't initialize with BuildProviders.
if p . name == "" {
p . name = providerName
}
2022-09-12 15:40:09 +00:00
config := & consul . Config {
ConnectionTimeout : 3 * time . Second ,
Token : p . token ,
Namespace : p . namespace ,
}
if p . tls != nil {
var err error
config . TLS , err = p . tls . CreateTLSConfig ( context . Background ( ) )
if err != nil {
return fmt . Errorf ( "unable to create client TLS configuration: %w" , err )
}
}
return p . Provider . Init ( consul . StoreName , p . name , config )
2019-11-28 20:56:04 +00:00
}