// Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *ConsulCatalog) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { config := api.DefaultConfig() config.Address = provider.Endpoint client, err := api.NewClient(config) if err != nil { return err } provider.client = client provider.Constraints = append(provider.Constraints, constraints...) pool.Go(func(stop chan bool) { notify := func(err error, time time.Duration) { log.Errorf("Consul connection error %+v, retrying in %s", err, time) } worker := func() error { return provider.watch(configurationChan, stop) } err := backoff.RetryNotify(worker, backoff.NewExponentialBackOff(), notify) if err != nil { log.Fatalf("Cannot connect to consul server %+v", err) } }) return err }
func (provider *Kv) provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error { provider.Constraints = append(provider.Constraints, constraints...) operation := func() error { if _, err := provider.kvclient.Exists("qmslkjdfmqlskdjfmqlksjazçueznbvbwzlkajzebvkwjdcqmlsfj"); err != nil { return fmt.Errorf("Failed to test KV store connection: %v", err) } if provider.Watch { pool.Go(func(stop chan bool) { err := provider.watchKv(configurationChan, provider.Prefix, stop) if err != nil { log.Errorf("Cannot watch KV store: %v", err) } }) } configuration := provider.loadConfig() configurationChan <- types.ConfigMessage{ ProviderName: string(provider.storeType), Configuration: configuration, } return nil } notify := func(err error, time time.Duration) { log.Errorf("KV connection error: %+v, retrying in %s", err, time) } err := backoff.RetryNotify(operation, job.NewBackOff(backoff.NewExponentialBackOff()), notify) if err != nil { return fmt.Errorf("Cannot connect to KV server: %v", err) } return nil }
// Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error { k8sClient, err := provider.newK8sClient() if err != nil { return err } provider.Constraints = append(provider.Constraints, constraints...) pool.Go(func(stop chan bool) { operation := func() error { for { stopWatch := make(chan struct{}, 1) defer close(stopWatch) log.Debugf("Using label selector: '%s'", provider.LabelSelector) eventsChan, err := k8sClient.WatchAll(provider.LabelSelector, stopWatch) if err != nil { log.Errorf("Error watching kubernetes events: %v", err) timer := time.NewTimer(1 * time.Second) select { case <-timer.C: return err case <-stop: return nil } } for { select { case <-stop: return nil case event := <-eventsChan: log.Debugf("Received event from kubernetes %+v", event) templateObjects, err := provider.loadIngresses(k8sClient) if err != nil { return err } if reflect.DeepEqual(provider.lastConfiguration.Get(), templateObjects) { log.Debugf("Skipping event from kubernetes %+v", event) } else { provider.lastConfiguration.Set(templateObjects) configurationChan <- types.ConfigMessage{ ProviderName: "kubernetes", Configuration: provider.loadConfig(*templateObjects), } } } } } } notify := func(err error, time time.Duration) { log.Errorf("Kubernetes connection error %+v, retrying in %s", err, time) } err := backoff.RetryNotify(operation, job.NewBackOff(backoff.NewExponentialBackOff()), notify) if err != nil { log.Errorf("Cannot connect to Kubernetes server %+v", err) } }) return nil }
// Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *File) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ []types.Constraint) error { watcher, err := fsnotify.NewWatcher() if err != nil { log.Error("Error creating file watcher", err) return err } file, err := os.Open(provider.Filename) if err != nil { log.Error("Error opening file", err) return err } defer file.Close() if provider.Watch { // Process events pool.Go(func(stop chan bool) { defer watcher.Close() for { select { case <-stop: return case event := <-watcher.Events: if strings.Contains(event.Name, file.Name()) { log.Debug("File event:", event) configuration := provider.loadFileConfig(file.Name()) if configuration != nil { configurationChan <- types.ConfigMessage{ ProviderName: "file", Configuration: configuration, } } } case error := <-watcher.Errors: log.Error("Watcher event error", error) } } }) err = watcher.Add(filepath.Dir(file.Name())) if err != nil { log.Error("Error adding file watcher", err) return err } } configuration := provider.loadFileConfig(file.Name()) configurationChan <- types.ConfigMessage{ ProviderName: "file", Configuration: configuration, } return nil }
func (provider *Kv) provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error { 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, } } operation := func() error { kv, err := libkv.NewStore( provider.storeType, strings.Split(provider.Endpoint, ","), storeConfig, ) if err != nil { return err } if _, err := kv.List(""); err != nil { return err } provider.kvclient = kv if provider.Watch { pool.Go(func(stop chan bool) { provider.watchKv(configurationChan, provider.Prefix, stop) }) } configuration := provider.loadConfig() configurationChan <- types.ConfigMessage{ ProviderName: string(provider.storeType), Configuration: configuration, } return nil } notify := func(err error, time time.Duration) { log.Errorf("KV connection error %+v, retrying in %s", err, time) } err := backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify) if err != nil { log.Fatalf("Cannot connect to KV server %+v", err) } return nil }
// Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error { operation := func() error { config := marathon.NewDefaultConfig() config.URL = provider.Endpoint config.EventsTransport = marathon.EventsTransportSSE if provider.Basic != nil { config.HTTPBasicAuthUser = provider.Basic.HTTPBasicAuthUser config.HTTPBasicPassword = provider.Basic.HTTPBasicPassword } config.HTTPClient = &http.Client{ Transport: &http.Transport{ TLSClientConfig: provider.TLS, }, } client, err := marathon.NewClient(config) if err != nil { log.Errorf("Failed to create a client for marathon, error: %s", err) return err } provider.marathonClient = client update := make(marathon.EventsChannel, 5) if provider.Watch { if err := client.AddEventsListener(update, marathon.EVENTS_APPLICATIONS); err != nil { log.Errorf("Failed to register for events, %s", err) return err } pool.Go(func(stop chan bool) { defer close(update) for { select { case <-stop: return case event := <-update: log.Debug("Marathon event receveived", event) configuration := provider.loadMarathonConfig() if configuration != nil { configurationChan <- types.ConfigMessage{ ProviderName: "marathon", Configuration: configuration, } } } } }) } configuration := provider.loadMarathonConfig() configurationChan <- types.ConfigMessage{ ProviderName: "marathon", Configuration: configuration, } return nil } notify := func(err error, time time.Duration) { log.Errorf("Marathon connection error %+v, retrying in %s", err, time) } err := backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify) if err != nil { log.Fatalf("Cannot connect to Marathon server %+v", err) } return nil }
// Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error { // TODO register this routine in pool, and watch for stop channel safe.Go(func() { operation := func() error { var err error dockerClient, err := provider.createClient() if err != nil { log.Errorf("Failed to create a client for docker, error: %s", err) return err } version, err := dockerClient.ServerVersion(context.Background()) log.Debugf("Docker connection established with docker %s (API %s)", version.Version, version.APIVersion) containers, err := listContainers(dockerClient) if err != nil { log.Errorf("Failed to list containers for docker, error %s", err) return err } configuration := provider.loadDockerConfig(containers) configurationChan <- types.ConfigMessage{ ProviderName: "docker", Configuration: configuration, } if provider.Watch { ctx, cancel := context.WithCancel(context.Background()) f := filters.NewArgs() f.Add("type", "container") options := dockertypes.EventsOptions{ Filters: f, } eventHandler := events.NewHandler(events.ByAction) startStopHandle := func(m eventtypes.Message) { log.Debugf("Docker event received %+v", m) containers, err := listContainers(dockerClient) if err != nil { log.Errorf("Failed to list containers for docker, error %s", err) // Call cancel to get out of the monitor cancel() } configuration := provider.loadDockerConfig(containers) if configuration != nil { configurationChan <- types.ConfigMessage{ ProviderName: "docker", Configuration: configuration, } } } eventHandler.Handle("start", startStopHandle) eventHandler.Handle("die", startStopHandle) errChan := events.MonitorWithHandler(ctx, dockerClient, options, eventHandler) pool.Go(func(stop chan bool) { for { select { case <-stop: cancel() return } } }) if err := <-errChan; err != nil { return err } } return nil } notify := func(err error, time time.Duration) { log.Errorf("Docker connection error %+v, retrying in %s", err, time) } err := backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify) if err != nil { log.Fatalf("Cannot connect to docker server %+v", err) } }) return nil }
// Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error { provider.Constraints = append(provider.Constraints, constraints...) operation := func() error { config := marathon.NewDefaultConfig() config.URL = provider.Endpoint config.EventsTransport = marathon.EventsTransportSSE if provider.Basic != nil { config.HTTPBasicAuthUser = provider.Basic.HTTPBasicAuthUser config.HTTPBasicPassword = provider.Basic.HTTPBasicPassword } if len(provider.DCOSToken) > 0 { config.DCOSToken = provider.DCOSToken } TLSConfig, err := provider.TLS.CreateTLSConfig() if err != nil { return err } config.HTTPClient = &http.Client{ Transport: &http.Transport{ DialContext: (&net.Dialer{ KeepAlive: provider.KeepAlive * time.Second, Timeout: time.Second * provider.DialerTimeout, }).DialContext, TLSClientConfig: TLSConfig, }, } client, err := marathon.NewClient(config) if err != nil { log.Errorf("Failed to create a client for marathon, error: %s", err) return err } provider.marathonClient = client update := make(marathon.EventsChannel, 5) if provider.Watch { if err := client.AddEventsListener(update, marathon.EventIDApplications); err != nil { log.Errorf("Failed to register for events, %s", err) return err } pool.Go(func(stop chan bool) { defer close(update) for { select { case <-stop: return case event := <-update: log.Debug("Marathon event receveived", event) configuration := provider.loadMarathonConfig() if configuration != nil { configurationChan <- types.ConfigMessage{ ProviderName: "marathon", Configuration: configuration, } } } } }) } configuration := provider.loadMarathonConfig() configurationChan <- types.ConfigMessage{ ProviderName: "marathon", Configuration: configuration, } return nil } notify := func(err error, time time.Duration) { log.Errorf("Marathon connection error %+v, retrying in %s", err, time) } err := backoff.RetryNotify(operation, job.NewBackOff(backoff.NewExponentialBackOff()), notify) if err != nil { log.Errorf("Cannot connect to Marathon server %+v", err) } return nil }
// Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error { provider.Constraints = append(provider.Constraints, constraints...) // TODO register this routine in pool, and watch for stop channel safe.Go(func() { operation := func() error { var err error dockerClient, err := provider.createClient() if err != nil { log.Errorf("Failed to create a client for docker, error: %s", err) return err } ctx := context.Background() version, err := dockerClient.ServerVersion(ctx) log.Debugf("Docker connection established with docker %s (API %s)", version.Version, version.APIVersion) var dockerDataList []dockerData if provider.SwarmMode { dockerDataList, err = listServices(ctx, dockerClient) if err != nil { log.Errorf("Failed to list services for docker swarm mode, error %s", err) return err } } else { dockerDataList, err = listContainers(ctx, dockerClient) if err != nil { log.Errorf("Failed to list containers for docker, error %s", err) return err } } configuration := provider.loadDockerConfig(dockerDataList) configurationChan <- types.ConfigMessage{ ProviderName: "docker", Configuration: configuration, } if provider.Watch { ctx, cancel := context.WithCancel(ctx) if provider.SwarmMode { // TODO: This need to be change. Linked to Swarm events docker/docker#23827 ticker := time.NewTicker(SwarmDefaultWatchTime) pool.Go(func(stop chan bool) { for { select { case <-ticker.C: services, err := listServices(ctx, dockerClient) if err != nil { log.Errorf("Failed to list services for docker, error %s", err) return } configuration := provider.loadDockerConfig(services) if configuration != nil { configurationChan <- types.ConfigMessage{ ProviderName: "docker", Configuration: configuration, } } case <-stop: ticker.Stop() cancel() return } } }) } else { pool.Go(func(stop chan bool) { for { select { case <-stop: cancel() return } } }) f := filters.NewArgs() f.Add("type", "container") options := dockertypes.EventsOptions{ Filters: f, } eventHandler := events.NewHandler(events.ByAction) startStopHandle := func(m eventtypes.Message) { log.Debugf("Docker event received %+v", m) containers, err := listContainers(ctx, dockerClient) if err != nil { log.Errorf("Failed to list containers for docker, error %s", err) // Call cancel to get out of the monitor cancel() return } configuration := provider.loadDockerConfig(containers) if configuration != nil { configurationChan <- types.ConfigMessage{ ProviderName: "docker", Configuration: configuration, } } } eventHandler.Handle("start", startStopHandle) eventHandler.Handle("die", startStopHandle) eventHandler.Handle("health_status: healthy", startStopHandle) eventHandler.Handle("health_status: unhealthy", startStopHandle) eventHandler.Handle("health_status: starting", startStopHandle) errChan := events.MonitorWithHandler(ctx, dockerClient, options, eventHandler) if err := <-errChan; err != nil { return err } } } return nil } notify := func(err error, time time.Duration) { log.Errorf("Docker connection error %+v, retrying in %s", err, time) } err := backoff.RetryNotify(operation, job.NewBackOff(backoff.NewExponentialBackOff()), notify) if err != nil { log.Errorf("Cannot connect to docker server %+v", err) } }) return nil }
// Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error { k8sClient, err := provider.createClient() if err != nil { return err } backOff := backoff.NewExponentialBackOff() provider.Constraints = append(provider.Constraints, constraints...) pool.Go(func(stop chan bool) { operation := func() error { for { stopWatch := make(chan bool, 5) defer close(stopWatch) eventsChan, errEventsChan, err := k8sClient.WatchAll(stopWatch) if err != nil { log.Errorf("Error watching kubernetes events: %v", err) timer := time.NewTimer(1 * time.Second) select { case <-timer.C: return err case <-stop: return nil } } Watch: for { select { case <-stop: stopWatch <- true return nil case err, ok := <-errEventsChan: stopWatch <- true if ok && strings.Contains(err.Error(), io.EOF.Error()) { // edge case, kubernetes long-polling disconnection break Watch } return err case event := <-eventsChan: log.Debugf("Received event from kubernetes %+v", event) templateObjects, err := provider.loadIngresses(k8sClient) if err != nil { return err } configurationChan <- types.ConfigMessage{ ProviderName: "kubernetes", Configuration: provider.loadConfig(*templateObjects), } } } } } notify := func(err error, time time.Duration) { log.Errorf("Kubernetes connection error %+v, retrying in %s", err, time) } err := backoff.RetryNotify(operation, backOff, notify) if err != nil { log.Fatalf("Cannot connect to Kubernetes server %+v", err) } }) templateObjects, err := provider.loadIngresses(k8sClient) if err != nil { return err } configurationChan <- types.ConfigMessage{ ProviderName: "kubernetes", Configuration: provider.loadConfig(*templateObjects), } return nil }