Exemplo n.º 1
0
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)
	}
}