Example #1
0
// TODO auth
func (this *Start) statusHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf8")
	w.Header().Set("Server", "ehaproxy")

	log.Info("%s status", r.RemoteAddr)

	var (
		wg       sync.WaitGroup
		mu       sync.Mutex
		aggStats = make(map[string]map[string]int64)
	)
	for i := 0; i < ctx.NumCPU(); i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()

			uri := fmt.Sprintf("http://127.0.0.1:%d/stats?stats;csv", i+dashboardPortHead)
			stats := fetchDashboardStats(uri)
			mu.Lock()
			for name, colVals := range stats {
				if _, present := aggStats[name]; !present {
					aggStats[name] = make(map[string]int64)
				}
				for k, v := range colVals {
					aggStats[name][k] += v
				}
			}
			mu.Unlock()
		}(i)
	}
	wg.Wait()

	b, _ := json.Marshal(aggStats)
	w.Write(b)
}
Example #2
0
func (this *Start) reload(kwInstances []string) {
	var servers = BackendServers{
		CpuNum:      ctx.NumCPU(),
		HaproxyRoot: this.root,
		ForwardFor:  this.forwardFor,
		PubPort:     this.pubPort,
		SubPort:     this.subPort,
		ManPort:     this.manPort,
	}
	servers.reset()
	for _, kwNode := range kwInstances {
		data, _, err := this.zkzone.Conn().Get(kwNode)
		if err != nil {
			log.Error("%s: %v", kwNode, err)
			continue
		}

		info := make(map[string]string)
		if err = json.Unmarshal([]byte(data), &info); err != nil {
			log.Error("%s: %v", data, err)
			continue
		}

		// pub
		if info["pub"] != "" {
			_, port, _ := net.SplitHostPort(info["pub"])
			be := Backend{
				Name: "p" + info["id"],
				Addr: info["pub"],
				Cpu:  info["cpu"],
				Port: port,
			}
			servers.Pub = append(servers.Pub, be)
		}

		// sub
		if info["sub"] != "" {
			_, port, _ := net.SplitHostPort(info["sub"])
			be := Backend{
				Name: "s" + info["id"],
				Addr: info["sub"],
				Cpu:  info["cpu"],
				Port: port,
			}
			servers.Sub = append(servers.Sub, be)
		}

		// man
		if info["man"] != "" {
			_, port, _ := net.SplitHostPort(info["man"])
			be := Backend{
				Name: "m" + info["id"],
				Addr: info["man"],
				Cpu:  info["cpu"],
				Port: port,
			}
			servers.Man = append(servers.Man, be)
		}
	}

	for i := 0; i < ctx.NumCPU(); i++ {
		servers.Dashboard = append(servers.Dashboard, Backend{
			Port: fmt.Sprintf("%d", dashboardPortHead+i),
			Name: fmt.Sprintf("%d", i+1), // process id starts from 1
		})
	}

	if servers.empty() {
		log.Warn("empty backend servers, all shutdown?")
		return
	}

	if reflect.DeepEqual(this.lastServers, servers) {
		log.Warn("backend servers stays unchanged")
		return
	}

	this.lastServers = servers
	if err := this.createConfigFile(servers); err != nil {
		log.Error(err)
		return
	}

	if err := this.reloadHAproxy(); err != nil {
		log.Error("reloading haproxy: %v", err)
		panic(err)
	}
}
Example #3
0
// TODO
// 1. broker id assignment
// 2. port assignment
func (this *Deploy) Run(args []string) (exitCode int) {
	cmdFlags := flag.NewFlagSet("deploy", flag.ContinueOnError)
	cmdFlags.Usage = func() { this.Ui.Output(this.Help()) }
	cmdFlags.StringVar(&this.zone, "z", "", "")
	cmdFlags.StringVar(&this.cluster, "c", "", "")
	cmdFlags.StringVar(&this.kafkaBaseDir, "kafka.base", ctx.KafkaHome(), "")
	cmdFlags.StringVar(&this.brokerId, "broker.id", "", "")
	cmdFlags.StringVar(&this.tcpPort, "port", "", "")
	cmdFlags.StringVar(&this.rootPah, "root", "/var/wd", "")
	cmdFlags.StringVar(&this.ip, "ip", "", "")
	cmdFlags.StringVar(&this.logDirs, "log.dirs", "", "")
	cmdFlags.StringVar(&this.runAs, "user", "sre", "")
	cmdFlags.StringVar(&this.uninstall, "uninstall", "", "")
	cmdFlags.BoolVar(&this.demoMode, "demo", false, "")
	cmdFlags.BoolVar(&this.installKafkaOnly, "kfkonly", false, "")
	cmdFlags.BoolVar(&this.dryRun, "dryrun", true, "")
	cmdFlags.StringVar(&this.influxDbAddr, "influx", "", "")
	cmdFlags.StringVar(&this.kafkaVer, "ver", "2.10-0.8.2.2", "")
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	if this.uninstall != "" {
		serverProperties := fmt.Sprintf("%s/config/server.properties", this.uninstall)
		lines, err := gio.ReadLines(serverProperties)
		if err != nil {
			this.Ui.Error(err.Error())
			return 2
		}
		var logDirs []string
		for _, line := range lines {
			if strings.HasPrefix(line, "log.dirs") {
				parts := strings.SplitN(line, "=", 2)
				logDirs = strings.Split(parts[1], ",")
				break
			}
		}
		if len(logDirs) == 0 {
			this.Ui.Error("empty log.dirs")
			return 2
		}

		for _, logDir := range logDirs {
			this.Ui.Output(fmt.Sprintf("rm -rf %s", logDir))
		}
		name := filepath.Base(this.uninstall)
		this.Ui.Output(fmt.Sprintf("chkconfig --del %s", name))
		this.Ui.Output(fmt.Sprintf("rm -f /etc/init.d/%s", name))
		this.Ui.Output(fmt.Sprintf("rm -rf %s", this.uninstall))
		return 0
	}

	if !ctx.CurrentUserIsRoot() {
		this.Ui.Error("requires root priviledges!")
		return 1
	}

	if !strings.HasSuffix(this.kafkaBaseDir, this.kafkaVer) {
		this.Ui.Error(fmt.Sprintf("kafka.base[%s] does not match ver[%s]",
			this.kafkaBaseDir, this.kafkaVer))
		return 1
	}

	if this.installKafkaOnly {
		this.installKafka()
		return
	}

	if validateArgs(this, this.Ui).
		require("-z", "-c").
		invalid(args) {
		return 2
	}

	this.zkzone = zk.NewZkZone(zk.DefaultConfig(this.zone, ctx.ZoneZkAddrs(this.zone)))
	clusers := this.zkzone.Clusters()
	zkchroot, present := clusers[this.cluster]
	if !present {
		this.Ui.Error(fmt.Sprintf("run 'gk clusters -z %s -add %s -p $zkchroot' first!",
			this.zone, this.cluster))
		return 1
	}

	var err error
	this.userInfo, err = user.Lookup(this.runAs)
	swallow(err)

	if this.demoMode {
		this.demo()
		return
	}

	if validateArgs(this, this.Ui).
		require("-broker.id", "-port", "-ip", "-log.dirs").
		invalid(args) {
		return 2
	}

	if this.dryRun {
		this.Ui.Output(fmt.Sprintf("mkdir %s/logs and chown to %s",
			this.instanceDir(), this.runAs))
	}
	err = os.MkdirAll(fmt.Sprintf("%s/logs", this.instanceDir()), 0755)
	swallow(err)
	chown(fmt.Sprintf("%s/logs", this.instanceDir()), this.userInfo)

	invalidDir := this.validateLogDirs(this.logDirs)
	if invalidDir != "" {
		this.Ui.Error(fmt.Sprintf("%s in log.dirs not exists!", invalidDir))
		return 2
	}

	// prepare the root directory
	this.rootPah = strings.TrimSuffix(this.rootPah, "/")
	if this.dryRun {
		this.Ui.Output(fmt.Sprintf("mkdir %s/bin and chown to %s",
			this.instanceDir(), this.runAs))
	}
	err = os.MkdirAll(fmt.Sprintf("%s/bin", this.instanceDir()), 0755)
	swallow(err)
	chown(fmt.Sprintf("%s/bin", this.instanceDir()), this.userInfo)

	if this.dryRun {
		this.Ui.Output(fmt.Sprintf("mkdir %s/config and chown to %s",
			this.instanceDir(), this.runAs))
	}
	err = os.MkdirAll(fmt.Sprintf("%s/config", this.instanceDir()), 0755)
	swallow(err)
	chown(fmt.Sprintf("%s/config", this.instanceDir()), this.userInfo)

	type templateVar struct {
		KafkaBase             string
		BrokerId              string
		TcpPort               string
		Ip                    string
		User                  string
		ZkChroot              string
		ZkAddrs               string
		InstanceDir           string
		LogDirs               string
		IoThreads             string
		NetworkThreads        string
		InfluxReporterEnabled string
		InfluxDbHost          string
		InfluxDbPort          string
	}
	if this.influxDbAddr != "" {
		this.influxDbHost, this.influxdbPort, err = net.SplitHostPort(this.influxDbAddr)
		if err != nil {
			this.Ui.Error(err.Error())
			return 2
		}
		if this.influxDbHost == "" || this.influxdbPort == "" {
			this.Ui.Error("empty influxdb host or port")
			return 2
		}
	}

	influxReporterEnabled := "false"
	if this.influxDbHost != "" {
		influxReporterEnabled = "true"
	}
	data := templateVar{
		ZkAddrs:               this.zkzone.ZkAddrs(),
		ZkChroot:              zkchroot,
		KafkaBase:             this.kafkaBaseDir,
		BrokerId:              this.brokerId,
		Ip:                    this.ip,
		InstanceDir:           this.instanceDir(),
		User:                  this.runAs,
		TcpPort:               this.tcpPort,
		LogDirs:               this.logDirs,
		InfluxReporterEnabled: influxReporterEnabled,
		InfluxDbHost:          this.influxDbHost,
		InfluxDbPort:          this.influxdbPort,
	}
	data.IoThreads = strconv.Itoa(3 * len(strings.Split(data.LogDirs, ",")))
	networkThreads := ctx.NumCPU() / 2
	if networkThreads < 2 {
		networkThreads = 2
	}
	data.NetworkThreads = strconv.Itoa(networkThreads) // TODO not used yet

	// create the log.dirs directory and chown to sre
	logDirs := strings.Split(this.logDirs, ",")
	for _, logDir := range logDirs {
		if this.dryRun {
			this.Ui.Output(fmt.Sprintf("mkdir %s and chown to %s",
				logDir, this.runAs))
		}

		swallow(os.MkdirAll(logDir, 0755))
		chown(logDir, this.userInfo)
	}

	// package the kafka runtime together
	if !gio.DirExists(this.kafkaLibDir()) {
		this.installKafka()
	}

	// bin
	writeFileFromTemplate("template/bin/kafka-topics.sh",
		fmt.Sprintf("%s/bin/kafka-topics.sh", this.instanceDir()), 0755, nil, this.userInfo)
	writeFileFromTemplate("template/bin/kafka-reassign-partitions.sh",
		fmt.Sprintf("%s/bin/kafka-reassign-partitions.sh", this.instanceDir()), 0755, nil, this.userInfo)
	writeFileFromTemplate("template/bin/kafka-preferred-replica-election.sh",
		fmt.Sprintf("%s/bin/kafka-preferred-replica-election.sh", this.instanceDir()), 0755, nil, this.userInfo)

	writeFileFromTemplate("template/bin/kafka-run-class.sh",
		fmt.Sprintf("%s/bin/kafka-run-class.sh", this.instanceDir()), 0755, data, this.userInfo)
	writeFileFromTemplate("template/bin/kafka-server-start.sh",
		fmt.Sprintf("%s/bin/kafka-server-start.sh", this.instanceDir()), 0755, data, this.userInfo)
	writeFileFromTemplate("template/bin/setenv.sh",
		fmt.Sprintf("%s/bin/setenv.sh", this.instanceDir()), 0755, data, this.userInfo)

	// /etc/init.d/
	writeFileFromTemplate("template/init.d/kafka",
		fmt.Sprintf("/etc/init.d/%s", this.clusterName()), 0755, data, nil)

	// config
	writeFileFromTemplate("template/config/server.properties",
		fmt.Sprintf("%s/config/server.properties", this.instanceDir()), 0644, data, this.userInfo)
	writeFileFromTemplate("template/config/log4j.properties",
		fmt.Sprintf("%s/config/log4j.properties", this.instanceDir()), 0644, data, this.userInfo)

	this.Ui.Warn(fmt.Sprintf("NOW, please run the following command:"))
	this.Ui.Output(color.Red("confirm log.retention.hours"))
	this.Ui.Output(color.Red("chkconfig --add %s", this.clusterName()))
	this.Ui.Output(color.Red("/etc/init.d/%s start", this.clusterName()))

	return
}
Example #4
0
func (this *Start) main() {
	ctx.LoadFromHome()

	// TODO zk session timeout
	err := etclib.Dial(strings.Split(ctx.ZoneZkAddrs(this.zone), ","))
	swalllow(err)

	root := zkr.Root(this.zone)
	ch := make(chan []string, 10)
	go etclib.WatchChildren(root, ch)

	var servers = BackendServers{
		CpuNum:      ctx.NumCPU(),
		HaproxyRoot: this.root,
		ForwardFor:  this.forwardFor,
		PubPort:     this.pubPort,
		SubPort:     this.subPort,
		ManPort:     this.manPort,
	}
	var lastInstances []string
	for {
		select {
		case <-this.quitCh:
			time.Sleep(time.Second) // FIXME just wait log flush
			return

		case <-ch:
			kwInstances, err := etclib.Children(root)
			if err != nil {
				log.Error("%s: %v", root, err)
				continue
			}

			log.Info("kateway ids: %+v -> %+v", lastInstances, kwInstances)
			lastInstances = kwInstances

			servers.reset()
			for _, kwId := range kwInstances {
				kwNode := fmt.Sprintf("%s/%s", root, kwId)
				data, err := etclib.Get(kwNode)
				if err != nil {
					log.Error("%s: %v", kwNode, err)
					continue
				}

				info := make(map[string]string)
				if err = json.Unmarshal([]byte(data), &info); err != nil {
					log.Error("%s: %v", data, err)
					continue
				}

				// pub
				if info["pub"] != "" {
					be := Backend{
						Name: "p" + info["id"],
						Addr: info["pub"],
						Cpu:  info["cpu"],
					}
					servers.Pub = append(servers.Pub, be)
				}

				// sub
				if info["sub"] != "" {
					be := Backend{
						Name: "s" + info["id"],
						Addr: info["sub"],
						Cpu:  info["cpu"],
					}
					servers.Sub = append(servers.Sub, be)
				}

				// man
				if info["man"] != "" {
					be := Backend{
						Name: "m" + info["id"],
						Addr: info["man"],
						Cpu:  info["cpu"],
					}
					servers.Man = append(servers.Man, be)
				}

			}

			if err = this.createConfigFile(servers); err != nil {
				log.Error(err)
				continue
			}

			if err = this.reloadHAproxy(); err != nil {
				log.Error("reloading haproxy: %v", err)
				panic(err)
			}

		}
	}
}