2018-11-14 09:18:03 +00:00
|
|
|
package aggregator
|
|
|
|
|
|
|
|
import (
|
2022-02-07 10:58:04 +00:00
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
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/config/dynamic"
|
|
|
|
"github.com/traefik/traefik/v2/pkg/config/static"
|
|
|
|
"github.com/traefik/traefik/v2/pkg/provider"
|
|
|
|
"github.com/traefik/traefik/v2/pkg/provider/file"
|
2021-01-28 15:16:05 +00:00
|
|
|
"github.com/traefik/traefik/v2/pkg/provider/traefik"
|
2022-01-24 10:08:05 +00:00
|
|
|
"github.com/traefik/traefik/v2/pkg/redactor"
|
2020-09-16 13:46:04 +00:00
|
|
|
"github.com/traefik/traefik/v2/pkg/safe"
|
2018-11-14 09:18:03 +00:00
|
|
|
)
|
|
|
|
|
2022-02-07 10:58:04 +00:00
|
|
|
// throttled defines what kind of config refresh throttling the aggregator should
|
|
|
|
// set up for a given provider.
|
|
|
|
// If a provider implements throttled, the configuration changes it sends will be
|
|
|
|
// taken into account no more often than the frequency inferred from ThrottleDuration().
|
|
|
|
// If ThrottleDuration returns zero, no throttling will take place.
|
|
|
|
// If throttled is not implemented, the throttling will be set up in accordance
|
|
|
|
// with the global providersThrottleDuration option.
|
|
|
|
type throttled interface {
|
|
|
|
ThrottleDuration() time.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
// maybeThrottledProvide returns the Provide method of the given provider,
|
|
|
|
// potentially augmented with some throttling depending on whether and how the
|
|
|
|
// provider implements the throttled interface.
|
|
|
|
func maybeThrottledProvide(prd provider.Provider, defaultDuration time.Duration) func(chan<- dynamic.Message, *safe.Pool) error {
|
|
|
|
providerThrottleDuration := defaultDuration
|
|
|
|
if throttled, ok := prd.(throttled); ok {
|
|
|
|
// per-provider throttling
|
|
|
|
providerThrottleDuration = throttled.ThrottleDuration()
|
|
|
|
}
|
|
|
|
|
|
|
|
if providerThrottleDuration == 0 {
|
|
|
|
// throttling disabled
|
|
|
|
return prd.Provide
|
|
|
|
}
|
|
|
|
|
|
|
|
return func(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
|
|
|
|
rc := newRingChannel()
|
|
|
|
pool.GoCtx(func(ctx context.Context) {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case msg := <-rc.out():
|
|
|
|
configurationChan <- msg
|
|
|
|
time.Sleep(providerThrottleDuration)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
return prd.Provide(rc.in(), pool)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
// ProviderAggregator aggregates providers.
|
|
|
|
type ProviderAggregator struct {
|
2022-02-07 10:58:04 +00:00
|
|
|
internalProvider provider.Provider
|
|
|
|
fileProvider provider.Provider
|
|
|
|
providers []provider.Provider
|
|
|
|
providersThrottleDuration time.Duration
|
2018-11-14 09:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewProviderAggregator returns an aggregate of all the providers configured in the static configuration.
|
2018-11-27 16:42:04 +00:00
|
|
|
func NewProviderAggregator(conf static.Providers) ProviderAggregator {
|
2022-02-07 10:58:04 +00:00
|
|
|
p := ProviderAggregator{
|
|
|
|
providersThrottleDuration: time.Duration(conf.ProvidersThrottleDuration),
|
|
|
|
}
|
2018-11-14 09:18:03 +00:00
|
|
|
|
|
|
|
if conf.File != nil {
|
|
|
|
p.quietAddProvider(conf.File)
|
|
|
|
}
|
|
|
|
|
2019-01-18 14:18:04 +00:00
|
|
|
if conf.Docker != nil {
|
|
|
|
p.quietAddProvider(conf.Docker)
|
|
|
|
}
|
|
|
|
|
2018-12-03 10:32:05 +00:00
|
|
|
if conf.Rest != nil {
|
|
|
|
p.quietAddProvider(conf.Rest)
|
|
|
|
}
|
|
|
|
|
2019-07-08 19:36:03 +00:00
|
|
|
if conf.KubernetesIngress != nil {
|
|
|
|
p.quietAddProvider(conf.KubernetesIngress)
|
2019-02-21 22:08:05 +00:00
|
|
|
}
|
|
|
|
|
2019-03-14 14:56:06 +00:00
|
|
|
if conf.KubernetesCRD != nil {
|
|
|
|
p.quietAddProvider(conf.KubernetesCRD)
|
|
|
|
}
|
2019-06-11 13:12:04 +00:00
|
|
|
|
2020-12-15 15:40:05 +00:00
|
|
|
if conf.KubernetesGateway != nil {
|
|
|
|
p.quietAddProvider(conf.KubernetesGateway)
|
|
|
|
}
|
|
|
|
|
2020-07-15 14:28:04 +00:00
|
|
|
if conf.Ecs != nil {
|
|
|
|
p.quietAddProvider(conf.Ecs)
|
|
|
|
}
|
|
|
|
|
2019-10-15 15:34:08 +00:00
|
|
|
if conf.ConsulCatalog != nil {
|
2022-06-03 10:00:09 +00:00
|
|
|
for _, pvd := range conf.ConsulCatalog.BuildProviders() {
|
|
|
|
p.quietAddProvider(pvd)
|
|
|
|
}
|
2019-10-15 15:34:08 +00:00
|
|
|
}
|
|
|
|
|
2022-06-10 16:32:08 +00:00
|
|
|
if conf.Nomad != nil {
|
2022-09-19 14:26:08 +00:00
|
|
|
for _, pvd := range conf.Nomad.BuildProviders() {
|
|
|
|
p.quietAddProvider(pvd)
|
|
|
|
}
|
2022-06-10 16:32:08 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 20:56:04 +00:00
|
|
|
if conf.Consul != nil {
|
2022-06-03 10:00:09 +00:00
|
|
|
for _, pvd := range conf.Consul.BuildProviders() {
|
|
|
|
p.quietAddProvider(pvd)
|
|
|
|
}
|
2019-11-28 20:56:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if conf.Etcd != nil {
|
|
|
|
p.quietAddProvider(conf.Etcd)
|
|
|
|
}
|
|
|
|
|
|
|
|
if conf.ZooKeeper != nil {
|
|
|
|
p.quietAddProvider(conf.ZooKeeper)
|
|
|
|
}
|
|
|
|
|
|
|
|
if conf.Redis != nil {
|
|
|
|
p.quietAddProvider(conf.Redis)
|
|
|
|
}
|
|
|
|
|
2020-07-15 14:56:03 +00:00
|
|
|
if conf.HTTP != nil {
|
|
|
|
p.quietAddProvider(conf.HTTP)
|
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *ProviderAggregator) quietAddProvider(provider provider.Provider) {
|
|
|
|
err := p.AddProvider(provider)
|
|
|
|
if err != nil {
|
2022-11-21 17:36:05 +00:00
|
|
|
log.Error().Err(err).Msgf("Error while initializing provider %T", provider)
|
2018-11-14 09:18:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddProvider adds a provider in the providers map.
|
|
|
|
func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
|
2018-11-27 16:42:04 +00:00
|
|
|
err := provider.Init()
|
2018-11-14 09:18:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-03-14 08:30:04 +00:00
|
|
|
|
2021-01-28 15:16:05 +00:00
|
|
|
switch provider.(type) {
|
|
|
|
case *file.Provider:
|
|
|
|
p.fileProvider = provider
|
|
|
|
case *traefik.Provider:
|
|
|
|
p.internalProvider = provider
|
|
|
|
default:
|
2019-03-14 08:30:04 +00:00
|
|
|
p.providers = append(p.providers, provider)
|
|
|
|
}
|
2021-01-28 15:16:05 +00:00
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-11 10:06:07 +00:00
|
|
|
// Init the provider.
|
2018-11-27 16:42:04 +00:00
|
|
|
func (p ProviderAggregator) Init() error {
|
2018-11-14 09:18:03 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-11 10:06:07 +00:00
|
|
|
// Provide calls the provide method of every providers.
|
2019-07-10 07:26:04 +00:00
|
|
|
func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
|
2021-02-01 11:36:03 +00:00
|
|
|
if p.fileProvider != nil {
|
2022-02-07 10:58:04 +00:00
|
|
|
p.launchProvider(configurationChan, pool, p.fileProvider)
|
2021-02-01 11:36:03 +00:00
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
for _, prd := range p.providers {
|
2019-03-19 09:04:04 +00:00
|
|
|
prd := prd
|
2018-11-14 09:18:03 +00:00
|
|
|
safe.Go(func() {
|
2022-02-07 10:58:04 +00:00
|
|
|
p.launchProvider(configurationChan, pool, prd)
|
2018-11-14 09:18:03 +00:00
|
|
|
})
|
|
|
|
}
|
2021-01-28 15:16:05 +00:00
|
|
|
|
2021-02-25 16:20:04 +00:00
|
|
|
// internal provider must be the last because we use it to know if all the providers are loaded.
|
|
|
|
// ConfigurationWatcher will wait for this requiredProvider before applying configurations.
|
|
|
|
if p.internalProvider != nil {
|
2022-02-07 10:58:04 +00:00
|
|
|
p.launchProvider(configurationChan, pool, p.internalProvider)
|
2021-02-25 16:20:04 +00:00
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
return nil
|
|
|
|
}
|
2019-03-14 08:30:04 +00:00
|
|
|
|
2022-02-07 10:58:04 +00:00
|
|
|
func (p ProviderAggregator) launchProvider(configurationChan chan<- dynamic.Message, pool *safe.Pool, prd provider.Provider) {
|
2022-01-24 10:08:05 +00:00
|
|
|
jsonConf, err := redactor.RemoveCredentials(prd)
|
2019-03-14 08:30:04 +00:00
|
|
|
if err != nil {
|
2022-11-21 17:36:05 +00:00
|
|
|
log.Debug().Err(err).Msgf("Cannot marshal the provider configuration %T", prd)
|
2019-03-14 08:30:04 +00:00
|
|
|
}
|
|
|
|
|
2022-11-21 17:36:05 +00:00
|
|
|
log.Info().Msgf("Starting provider %T", prd)
|
|
|
|
log.Debug().RawJSON("config", []byte(jsonConf)).Msgf("%T provider configuration", prd)
|
2019-03-14 08:30:04 +00:00
|
|
|
|
2022-02-07 10:58:04 +00:00
|
|
|
if err := maybeThrottledProvide(prd, p.providersThrottleDuration)(configurationChan, pool); err != nil {
|
2022-11-21 17:36:05 +00:00
|
|
|
log.Error().Err(err).Msgf("Cannot start the provider %T", prd)
|
2022-02-07 10:58:04 +00:00
|
|
|
return
|
2019-03-14 08:30:04 +00:00
|
|
|
}
|
|
|
|
}
|