func parseService(service swarmtypes.Service, networkMap map[string]*dockertypes.NetworkResource) dockerData { dockerData := dockerData{ Name: service.Spec.Annotations.Name, Labels: service.Spec.Annotations.Labels, NetworkSettings: networkSettings{}, } if service.Spec.EndpointSpec != nil { switch service.Spec.EndpointSpec.Mode { case swarm.ResolutionModeDNSRR: log.Debug("Ignored endpoint-mode not supported, service name: %s", dockerData.Name) case swarm.ResolutionModeVIP: dockerData.NetworkSettings.Networks = make(map[string]*networkData) for _, virtualIP := range service.Endpoint.VirtualIPs { networkService := networkMap[virtualIP.NetworkID] if networkService != nil { ip, _, _ := net.ParseCIDR(virtualIP.Addr) network := &networkData{ Name: networkService.Name, ID: virtualIP.NetworkID, Addr: ip.String(), } dockerData.NetworkSettings.Networks[network.Name] = network } else { log.Debug("Network not found, id: %s", virtualIP.NetworkID) } } } } return dockerData }
func (provider *ConsulCatalog) watch(configurationChan chan<- types.ConfigMessage, stop chan bool) error { stopCh := make(chan struct{}) serviceCatalog := provider.watchServices(stopCh) defer close(stopCh) for { select { case <-stop: return nil case index, ok := <-serviceCatalog: if !ok { return errors.New("Consul service list nil") } log.Debug("List of services changed") nodes, err := provider.getNodes(index) if err != nil { return err } configuration := provider.buildConfig(nodes) configurationChan <- types.ConfigMessage{ ProviderName: "consul_catalog", Configuration: configuration, } } } }
func listServices(ctx context.Context, dockerClient client.APIClient) ([]dockerData, error) { serviceList, err := dockerClient.ServiceList(ctx, dockertypes.ServiceListOptions{}) if err != nil { return []dockerData{}, err } networkListArgs := filters.NewArgs() networkListArgs.Add("driver", "overlay") networkList, err := dockerClient.NetworkList(ctx, dockertypes.NetworkListOptions{Filters: networkListArgs}) networkMap := make(map[string]*dockertypes.NetworkResource) if err != nil { log.Debug("Failed to network inspect on client for docker, error: %s", err) return []dockerData{}, err } for _, network := range networkList { networkToAdd := network networkMap[network.ID] = &networkToAdd } var dockerDataList []dockerData for _, service := range serviceList { dockerData := parseService(service, networkMap) dockerDataList = append(dockerDataList, dockerData) } return dockerDataList, err }
// 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, constraints types.Constraints) 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 }
// 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 }
func (provider *Marathon) taskFilter(task marathon.Task, applications *marathon.Applications, exposedByDefaultFlag bool) bool { if len(task.Ports) == 0 { log.Debug("Filtering marathon task without port %s", task.AppID) return false } application, err := getApplication(task, applications.Apps) if err != nil { log.Errorf("Unable to get marathon application from task %s", task.AppID) return false } label, _ := provider.getLabel(application, "traefik.tags") constraintTags := strings.Split(label, ",") if provider.MarathonLBCompatibility { if label, err := provider.getLabel(application, "HAPROXY_GROUP"); err == nil { constraintTags = append(constraintTags, label) } } if ok, failingConstraint := provider.MatchConstraints(constraintTags); !ok { if failingConstraint != nil { log.Debugf("Application %v pruned by '%v' constraint", application.ID, failingConstraint.String()) } return false } if !isApplicationEnabled(application, exposedByDefaultFlag) { log.Debugf("Filtering disabled marathon task %s", task.AppID) return false } //filter indeterminable task port portIndexLabel := (*application.Labels)["traefik.portIndex"] portValueLabel := (*application.Labels)["traefik.port"] if portIndexLabel != "" && portValueLabel != "" { log.Debugf("Filtering marathon task %s specifying both traefik.portIndex and traefik.port labels", task.AppID) return false } if portIndexLabel != "" { index, err := strconv.Atoi((*application.Labels)["traefik.portIndex"]) if err != nil || index < 0 || index > len(application.Ports)-1 { log.Debugf("Filtering marathon task %s with unexpected value for traefik.portIndex label", task.AppID) return false } } if portValueLabel != "" { port, err := strconv.Atoi((*application.Labels)["traefik.port"]) if err != nil { log.Debugf("Filtering marathon task %s with unexpected value for traefik.port label", task.AppID) return false } var foundPort bool for _, exposedPort := range task.Ports { if port == exposedPort { foundPort = true break } } if !foundPort { log.Debugf("Filtering marathon task %s without a matching port for traefik.port label", task.AppID) return false } } //filter healthchecks if application.HasHealthChecks() { if task.HasHealthCheckResults() { for _, healthcheck := range task.HealthCheckResults { // found one bad healthcheck, return false if !healthcheck.Alive { log.Debugf("Filtering marathon task %s with bad healthcheck", task.AppID) return false } } } } return true }