func (u *mesosUpstream) sync() { var syncing int32 syncing = atomic.AddInt32(&u.syncing, 1) if syncing > 1 { atomic.AddInt32(&u.syncing, -1) u.syncWg.Wait() return } u.syncWg.Add(1) defer func() { u.syncWg.Done() atomic.AddInt32(&u.syncing, -1) u.lastSync = time.Now() }() var state mesosState var masterHosts []string if path, err := url.Parse(u.mesosMaster); err == nil { switch path.Scheme { case "zk": if path.Path == "" || path.Path == "/" { log.Printf("[ERROR] no path specified for mesos zk lookup \"%s\"", u.mesosMaster) return } zookeeperPath := path.Path if zookeeperPath[0] != '/' { zookeeperPath = "/" + zookeeperPath } if zoo, _, err := zk.Connect(strings.Split(path.Host, ","), 10*time.Second); err == nil { defer zoo.Close() if children, _, err := zoo.Children(zookeeperPath); err == nil { sort.Strings(children) for _, child := range children { if strings.HasPrefix(child, "info_") { if data, _, err := zoo.Get(zookeeperPath + "/" + child); err == nil { masterInfo := new(mesosproto.MasterInfo) if err := masterInfo.Unmarshal(data); err == nil { masterHosts = []string{fmt.Sprintf("%s:%d", masterInfo.GetHostname(), masterInfo.GetPort())} break } else { log.Printf("[ERROR] parsing mesos master from zookeeper. \"%s\"", err.Error()) return } } else { log.Printf("[ERROR] getting mesos master from zookeeper. \"%s\"", err.Error()) return } } } } else { log.Printf("[ERROR] getting mesos masters from zookeeper. \"%s\"", err.Error()) return } } case "http", "https": masterHosts = strings.Split(path.Host, ",") default: log.Printf("[ERROR] unknown scheme in parsing mesos master url \"%s\"", u.mesosMaster) return } } else { masterHosts = strings.Split(u.mesosMaster, ",") } if len(masterHosts) == 0 { log.Printf("[ERROR] No reachable masters.") return } var masterErr error for _, host := range masterHosts { if resp, err := http.Get("http://" + host + "/state.json"); err == nil { defer resp.Body.Close() if err := json.NewDecoder(resp.Body).Decode(&state); err == nil { masterErr = nil break } else { masterErr = err } } else { masterErr = err } } if masterErr != nil { log.Printf("[ERROR] Failed to reach masters. \"%s\"", masterErr.Error()) return } if len(state.Frameworks) == 0 { log.Println("[WARNING] No frameworks found running.") return } hosts := make(proxy.HostPool, 0, 4) for _, framework := range state.Frameworks { if framework.Name == u.framework { for _, task := range framework.Tasks { if task.Name == u.taskName && task.State == "TASK_RUNNING" { host := &proxy.UpstreamHost{ Name: task.SlaveId, Conns: 0, Fails: 0, FailTimeout: u.FailTimeout, Unhealthy: false, ExtraHeaders: u.proxyHeaders, CheckDown: func(upstream *mesosUpstream) proxy.UpstreamHostDownFunc { return func(uh *proxy.UpstreamHost) bool { if uh.Unhealthy { return true } if uh.Fails >= upstream.MaxFails && upstream.MaxFails != 0 { return true } return false } }(u), } if u.Port > 0 { host.Name = host.Name + ":" + strconv.Itoa(u.Port) } else if u.Port < 0 { idx := (u.Port * -1) - 1 if len(task.Resources.Ports) > 2 { portResource := task.Resources.Ports[1 : len(task.Resources.Ports)-1] ports := strings.Split(portResource, " ") if idx < len(ports) { selectedPort := ports[idx] if strings.Index(selectedPort, "-") != -1 { selectedPort = strings.Split(selectedPort, "-")[0] host.Name = host.Name + ":" + selectedPort } } else { continue } } else { continue } } hosts = append(hosts, host) } } break } } for _, host := range hosts { id, port := func() (string, string) { k := strings.Split(host.Name, ":") return k[0], k[1] }() for _, slave := range state.Slaves { if id == slave.Id { host.Name = u.Scheme + "://" + slave.Hostname + ":" + port break } } } oldPool := u.Hosts() isSame := len(oldPool) == len(hosts) for i, host := range hosts { found := false for _, oldHost := range oldPool { if oldHost.Name == host.Name { hosts[i] = oldHost found = true break } } if !found { isSame = false } } for _, host := range hosts { if host.ReverseProxy == nil { if baseUrl, err := url.Parse(host.Name); err == nil { host.ReverseProxy = proxy.NewSingleHostReverseProxy(baseUrl, "") } else { return } } } if !isSame { if u.HealthCheck.Path != "" { u.healthCheck(hosts) } u.hosts.Store(hosts) } }