// tabletParamToTabletAlias takes either an old style ZK tablet path or a // new style tablet alias as a string, and returns a TabletAlias. func tabletParamToTabletAlias(param string) topo.TabletAlias { if param[0] == '/' { // old zookeeper path, convert to new-style string tablet alias zkPathParts := strings.Split(param, "/") if len(zkPathParts) != 6 || zkPathParts[0] != "" || zkPathParts[1] != "zk" || zkPathParts[3] != "vt" || zkPathParts[4] != "tablets" { log.Fatalf("Invalid tablet path: %v", param) } param = zkPathParts[2] + "-" + zkPathParts[5] } result, err := topo.ParseTabletAliasString(param) if err != nil { log.Fatalf("Invalid tablet alias %v: %v", param, err) } return result }
func main() { flag.Parse() servenv.Init() defer servenv.Close() templateLoader = NewTemplateLoader(*templateDir, dummyTemplate, *debug) ts = topo.GetServer() defer topo.CloseServers() wr := wrangler.New(logutil.NewConsoleLogger(), ts, 30*time.Second, 30*time.Second) actionRepo = NewActionRepository(ts) // keyspace actions actionRepo.RegisterKeyspaceAction("ValidateKeyspace", func(wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateKeyspace(keyspace, false) }) actionRepo.RegisterKeyspaceAction("ValidateSchemaKeyspace", func(wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateSchemaKeyspace(keyspace, nil, false) }) actionRepo.RegisterKeyspaceAction("ValidateVersionKeyspace", func(wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateVersionKeyspace(keyspace) }) actionRepo.RegisterKeyspaceAction("ValidatePermissionsKeyspace", func(wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidatePermissionsKeyspace(keyspace) }) // shard actions actionRepo.RegisterShardAction("ValidateShard", func(wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateShard(keyspace, shard, false) }) actionRepo.RegisterShardAction("ValidateSchemaShard", func(wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateSchemaShard(keyspace, shard, nil, false) }) actionRepo.RegisterShardAction("ValidateVersionShard", func(wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateVersionShard(keyspace, shard) }) actionRepo.RegisterShardAction("ValidatePermissionsShard", func(wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidatePermissionsShard(keyspace, shard) }) // tablet actions actionRepo.RegisterTabletAction("Ping", "", func(wr *wrangler.Wrangler, tabletAlias topo.TabletAlias, r *http.Request) (string, error) { ti, err := wr.TopoServer().GetTablet(tabletAlias) if err != nil { return "", err } return "", wr.TabletManagerClient().Ping(wr.Context(), ti) }) actionRepo.RegisterTabletAction("ScrapTablet", acl.ADMIN, func(wr *wrangler.Wrangler, tabletAlias topo.TabletAlias, r *http.Request) (string, error) { // refuse to scrap tablets that are not spare ti, err := wr.TopoServer().GetTablet(tabletAlias) if err != nil { return "", err } if ti.Type != topo.TYPE_SPARE { return "", fmt.Errorf("Can only scrap spare tablets") } return "", wr.Scrap(tabletAlias, false, false) }) actionRepo.RegisterTabletAction("ScrapTabletForce", acl.ADMIN, func(wr *wrangler.Wrangler, tabletAlias topo.TabletAlias, r *http.Request) (string, error) { // refuse to scrap tablets that are not spare ti, err := wr.TopoServer().GetTablet(tabletAlias) if err != nil { return "", err } if ti.Type != topo.TYPE_SPARE { return "", fmt.Errorf("Can only scrap spare tablets") } return "", wr.Scrap(tabletAlias, true, false) }) actionRepo.RegisterTabletAction("DeleteTablet", acl.ADMIN, func(wr *wrangler.Wrangler, tabletAlias topo.TabletAlias, r *http.Request) (string, error) { return "", wr.DeleteTablet(tabletAlias) }) // toplevel index http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { templateLoader.ServeTemplate("index.html", indexContent, w, r) }) // keyspace actions http.HandleFunc("/keyspace_actions", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpError(w, "cannot parse form: %s", err) return } action := r.FormValue("action") if action == "" { http.Error(w, "no action provided", http.StatusBadRequest) return } keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "no keyspace provided", http.StatusBadRequest) return } result := actionRepo.ApplyKeyspaceAction(action, keyspace, r) templateLoader.ServeTemplate("action.html", result, w, r) }) // shard actions http.HandleFunc("/shard_actions", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpError(w, "cannot parse form: %s", err) return } action := r.FormValue("action") if action == "" { http.Error(w, "no action provided", http.StatusBadRequest) return } keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "no keyspace provided", http.StatusBadRequest) return } shard := r.FormValue("shard") if shard == "" { http.Error(w, "no shard provided", http.StatusBadRequest) return } result := actionRepo.ApplyShardAction(action, keyspace, shard, r) templateLoader.ServeTemplate("action.html", result, w, r) }) // tablet actions http.HandleFunc("/tablet_actions", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpError(w, "cannot parse form: %s", err) return } action := r.FormValue("action") if action == "" { http.Error(w, "no action provided", http.StatusBadRequest) return } alias := r.FormValue("alias") if alias == "" { http.Error(w, "no alias provided", http.StatusBadRequest) return } tabletAlias, err := topo.ParseTabletAliasString(alias) if err != nil { http.Error(w, "bad alias provided", http.StatusBadRequest) return } result := actionRepo.ApplyTabletAction(action, tabletAlias, r) templateLoader.ServeTemplate("action.html", result, w, r) }) // topology server http.HandleFunc("/dbtopo", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpError(w, "cannot parse form: %s", err) return } result := DbTopologyResult{} topology, err := topotools.DbTopology(context.TODO(), wr.TopoServer()) if err != nil { result.Error = err.Error() } else { result.Topology = topology } templateLoader.ServeTemplate("dbtopo.html", result, w, r) }) // serving graph http.HandleFunc("/serving_graph/", func(w http.ResponseWriter, r *http.Request) { parts := strings.Split(r.URL.Path, "/") cell := parts[len(parts)-1] if cell == "" { cells, err := ts.GetKnownCells() if err != nil { httpError(w, "cannot get known cells: %v", err) return } else { templateLoader.ServeTemplate("serving_graph_cells.html", cells, w, r) } return } servingGraph := topotools.DbServingGraph(wr.TopoServer(), cell) templateLoader.ServeTemplate("serving_graph.html", servingGraph, w, r) }) // redirects for explorers http.HandleFunc("/explorers/redirect", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpError(w, "cannot parse form: %s", err) return } var explorer Explorer switch len(explorers) { case 0: http.Error(w, "no explorer configured", http.StatusInternalServerError) return case 1: for _, ex := range explorers { explorer = ex } default: explorerName := r.FormValue("explorer") var ok bool explorer, ok = explorers[explorerName] if !ok { http.Error(w, "bad explorer name", http.StatusBadRequest) return } } var target string switch r.FormValue("type") { case "keyspace": keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } target = explorer.GetKeyspacePath(keyspace) case "shard": keyspace, shard := r.FormValue("keyspace"), r.FormValue("shard") if keyspace == "" || shard == "" { http.Error(w, "keyspace and shard are obligatory for this redirect", http.StatusBadRequest) return } target = explorer.GetShardPath(keyspace, shard) case "srv_keyspace": cell := r.FormValue("cell") if cell == "" { http.Error(w, "cell is obligatory for this redirect", http.StatusBadRequest) return } keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } target = explorer.GetSrvKeyspacePath(cell, keyspace) case "srv_shard": cell := r.FormValue("cell") if cell == "" { http.Error(w, "cell is obligatory for this redirect", http.StatusBadRequest) return } keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } shard := r.FormValue("shard") if shard == "" { http.Error(w, "shard is obligatory for this redirect", http.StatusBadRequest) return } target = explorer.GetSrvShardPath(cell, keyspace, shard) case "srv_type": cell := r.FormValue("cell") if cell == "" { http.Error(w, "cell is obligatory for this redirect", http.StatusBadRequest) return } keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } shard := r.FormValue("shard") if shard == "" { http.Error(w, "shard is obligatory for this redirect", http.StatusBadRequest) return } tabletType := r.FormValue("tablet_type") if tabletType == "" { http.Error(w, "tablet_type is obligatory for this redirect", http.StatusBadRequest) return } target = explorer.GetSrvTypePath(cell, keyspace, shard, topo.TabletType(tabletType)) case "tablet": aliasName := r.FormValue("alias") if aliasName == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } alias, err := topo.ParseTabletAliasString(aliasName) if err != nil { http.Error(w, "bad tablet alias", http.StatusBadRequest) return } target = explorer.GetTabletPath(alias) case "replication": cell := r.FormValue("cell") if cell == "" { http.Error(w, "cell is obligatory for this redirect", http.StatusBadRequest) return } keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } shard := r.FormValue("shard") if shard == "" { http.Error(w, "shard is obligatory for this redirect", http.StatusBadRequest) return } target = explorer.GetReplicationSlaves(cell, keyspace, shard) default: http.Error(w, "bad redirect type", http.StatusBadRequest) return } http.Redirect(w, r, target, http.StatusFound) }) servenv.RunDefault() }