// 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) }
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) } }
// 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 }
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) } } } }