func main() { flag.Parse() args := flag.Args() installSignalHandlers() servenv.Init() defer servenv.Close() ts := topo.GetServer() defer topo.CloseServers() // the logger will be replaced when we start a job wr = wrangler.New(logutil.NewConsoleLogger(), ts, 30*time.Second, 30*time.Second) if len(args) == 0 { // interactive mode, initialize the web UI to chose a command initInteractiveMode() } else { // single command mode, just runs it runCommand(args) } initStatusHandling() servenv.RunDefault() }
func main() { flag.Parse() servenv.Init() defer servenv.Close() unmarshalFile(*dbConfigFile, &dbconfig) log.Infof("dbconfig: %s\n", dbconfig) unmarshalFile(*overridesFile, &schemaOverrides) data, _ := json.MarshalIndent(schemaOverrides, "", " ") log.Infof("schemaOverrides: %s\n", data) ts.InitQueryService() ts.AllowQueries(dbconfig, schemaOverrides, ts.LoadCustomRules()) servenv.ServeRPC() log.Infof("starting vtocc %v", *port) s := proc.ListenAndServe(fmt.Sprintf("%v", *port)) // A SIGUSR1 means that we're restarting if s == syscall.SIGUSR1 { // Give some time for the other process // to pick up the listeners time.Sleep(5 * time.Millisecond) ts.DisallowQueries(true) } else { ts.DisallowQueries(false) } }
func main() { defer exit.Recover() defer logutil.Flush() dbconfigs.RegisterFlags() flag.Parse() mycnf := mysqlctl.NewMycnf(uint32(*tabletUid), *mysqlPort) if *mysqlSocket != "" { mycnf.SocketFile = *mysqlSocket } dbcfgs, err := dbconfigs.Init(mycnf.SocketFile) if err != nil { log.Errorf("%v", err) exit.Return(255) } mysqld = mysqlctl.NewMysqld("Dba", mycnf, &dbcfgs.Dba, &dbcfgs.Repl) // Register OnTerm handler before mysqld starts, so we get notified if mysqld // dies on its own without us (or our RPC client) telling it to. mysqldTerminated := make(chan struct{}) mysqld.OnTerm(func() { close(mysqldTerminated) }) // Start or Init mysqld as needed. if _, err = os.Stat(mycnf.DataDir); os.IsNotExist(err) { log.Infof("mysql data dir (%s) doesn't exist, initializing", mycnf.DataDir) mysqld.Init(*waitTime, *bootstrapArchive, *skipSchema) } else { log.Infof("mysql data dir (%s) already exists, starting without init", mycnf.DataDir) mysqld.Start(*waitTime) } servenv.Init() defer servenv.Close() // Take mysqld down with us on SIGTERM before entering lame duck. servenv.OnTerm(func() { log.Infof("mysqlctl received SIGTERM, shutting down mysqld first") mysqld.Shutdown(false, 0) }) // Start RPC server and wait for SIGTERM. mysqlctldTerminated := make(chan struct{}) go func() { servenv.RunDefault() close(mysqlctldTerminated) }() select { case <-mysqldTerminated: log.Infof("mysqld shut down on its own, exiting mysqlctld") case <-mysqlctldTerminated: log.Infof("mysqlctld shut down gracefully") } }
func main() { flag.Parse() servenv.Init() defer servenv.Close() keyRange, err := key.ParseKeyRangeParts(*start, *end) if err != nil { log.Fatalf("Invalid key range: %v", err) } if *dbConfigFile == "" { log.Fatalf("Cannot start without db-config-file") } dbConfig, err := readDbConfig(*dbConfigFile) if err != nil { log.Fatalf("Cannot read db config file: %v", err) } var t []string if *tables != "" { t = strings.Split(*tables, ",") for i, table := range t { t[i] = strings.TrimSpace(table) } } interrupted := make(chan struct{}) c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGTERM) go func() { for _ = range c { close(interrupted) } }() var vtClient mysqlctl.VtClient vtClient = mysqlctl.NewDbClient(dbConfig) err = vtClient.Connect() if err != nil { log.Fatalf("error in initializing dbClient: %v", err) } brs, err := mysqlctl.ReadStartPosition(vtClient, uint32(*uid)) if err != nil { log.Fatalf("Cannot read start position from db: %v", err) } if *debug { vtClient = mysqlctl.NewDummyVtClient() } blp, err := mysqlctl.NewBinlogPlayer(vtClient, keyRange, uint32(*uid), brs, t, *txnBatch, time.Duration(*maxTxnInterval)*time.Second, *execDdl) if err != nil { log.Fatalf("error in initializing binlog player: %v", err) } err = blp.ApplyBinlogEvents(interrupted) if err != nil { log.Errorf("Error in applying binlog events, err %v", err) } log.Infof("vt_binlog_player done") }
// zkocc: a proxy for zk func main() { flag.Parse() servenv.Init() defer servenv.Close() servenv.ServeRPC() zkr := zkocc.NewZkReader(*resolveLocal, flag.Args()) zk.RegisterZkReader(zkr) topo.RegisterTopoReader(&TopoReader{zkr: zkr}) proc.ListenAndServe(fmt.Sprintf("%v", *port)) }
func main() { dbconfigs.RegisterFlags() mysqlctl.RegisterFlags() flag.Parse() servenv.Init() defer servenv.Close() log.Infof("started vtaction %v", os.Args) servenv.ServeRPC() mycnf, mycnfErr := mysqlctl.NewMycnfFromFlags(0) if mycnfErr != nil { log.Fatalf("mycnf read failed: %v", mycnfErr) } log.V(6).Infof("mycnf: %v", jscfg.ToJson(mycnf)) dbcfgs, cfErr := dbconfigs.Init(mycnf.SocketFile) if cfErr != nil { log.Fatalf("%s", cfErr) } mysqld := mysqlctl.NewMysqld("Dba", mycnf, &dbcfgs.Dba, &dbcfgs.Repl) defer mysqld.Close() topoServer := topo.GetServer() defer topo.CloseServers() actor := actor.NewTabletActor(mysqld, mysqld, topoServer, topo.TabletAlias{}) // we delegate out startup to the micromanagement server so these actions // will occur after we have obtained our socket. bindAddr := fmt.Sprintf(":%v", *servenv.Port) httpServer := &http.Server{Addr: bindAddr} go func() { if err := httpServer.ListenAndServe(); err != nil { log.Errorf("httpServer.ListenAndServe err: %v", err) } }() actionErr := actor.HandleAction(*actionNode, *action, *actionGuid, *force) if actionErr != nil { log.Fatalf("action error: %v", actionErr) } log.Infof("finished vtaction %v", os.Args) }
func main() { flag.Parse() servenv.Init() defer servenv.Close() ts = topo.GetServer() defer topo.CloseServers() // Init the vtctld core vtctld.InitVtctld(ts) // Start schema manager service. initSchema() // And run the server. servenv.RunDefault() }
func main() { defer exit.Recover() flag.Parse() args := flag.Args() servenv.Init() defer servenv.Close() ts := topo.GetServer() defer topo.CloseServers() wi = worker.NewInstance(ts, *cell, *commandDisplayInterval) wi.InstallSignalHandlers() wi.InitStatusHandling() if len(args) == 0 { // In interactive mode, initialize the web UI to choose a command. wi.InitInteractiveMode() } else { // In single command mode, just run it. worker, done, err := wi.RunCommand(context.Background(), args, nil /*custom wrangler*/, true /*runFromCli*/) if err != nil { log.Error(err) exit.Return(1) } // Run the subsequent, blocking wait asynchronously. go func() { if err := wi.WaitForCommand(worker, done); err != nil { log.Error(err) logutil.Flush() // We cannot use exit.Return() here because we are in a different go routine now. os.Exit(1) } logutil.Flush() os.Exit(0) }() } servenv.RunDefault() }
func main() { flag.Parse() args := flag.Args() installSignalHandlers() servenv.Init() defer servenv.Close() ts := topo.GetServer() defer topo.CloseServers() wr := wrangler.New(ts, 30*time.Second, 30*time.Second) if len(args) == 0 { // interactive mode, initialize the web UI to chose a command initInteractiveMode(wr) } else { runCommand(wr, args) } initStatusHandling() servenv.RunDefault() }
func main() { flag.Parse() servenv.Init() defer servenv.Close() if *mycnfFile == "" { log.Fatalf("Please specify the path for mycnf file.") } mycnf, err := mysqlctl.ReadMycnf(*mycnfFile) if err != nil { log.Fatalf("Error reading mycnf file %v", *mycnfFile) } binlogServer := mysqlctl.NewBinlogServer(mycnf) mysqlctl.EnableBinlogServerService(binlogServer, *dbname) proto.RegisterBinlogServer(binlogServer) rpcwrap.RegisterAuthenticated(binlogServer) servenv.ServeRPC() proc.ListenAndServe(fmt.Sprintf("%v", *port)) mysqlctl.DisableBinlogServerService(binlogServer) }
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("RpcPing", "", func(wr *wrangler.Wrangler, tabletAlias topo.TabletAlias, r *http.Request) (string, error) { return "", wr.ActionInitiator().RpcPing(tabletAlias, 10*time.Second) }) 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") } actionPath, err := wr.Scrap(tabletAlias, false, false) if err != nil { return "", err } return "", wr.WaitForCompletion(actionPath) }) 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") } _, err = wr.Scrap(tabletAlias, true, false) return "", err }) 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(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() }
func main() { flag.Parse() servenv.Init() defer servenv.Close() templateLoader = NewTemplateLoader(*templateDir, *debug) ts = topo.GetServer() defer topo.CloseServers() actionRepo = NewActionRepository(ts) // keyspace actions actionRepo.RegisterKeyspaceAction("ValidateKeyspace", func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateKeyspace(ctx, keyspace, false) }) actionRepo.RegisterKeyspaceAction("ValidateSchemaKeyspace", func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateSchemaKeyspace(ctx, keyspace, nil, false) }) actionRepo.RegisterKeyspaceAction("ValidateVersionKeyspace", func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateVersionKeyspace(ctx, keyspace) }) actionRepo.RegisterKeyspaceAction("ValidatePermissionsKeyspace", func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidatePermissionsKeyspace(ctx, keyspace) }) // shard actions actionRepo.RegisterShardAction("ValidateShard", func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateShard(ctx, keyspace, shard, false) }) actionRepo.RegisterShardAction("ValidateSchemaShard", func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateSchemaShard(ctx, keyspace, shard, nil, false) }) actionRepo.RegisterShardAction("ValidateVersionShard", func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateVersionShard(ctx, keyspace, shard) }) actionRepo.RegisterShardAction("ValidatePermissionsShard", func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidatePermissionsShard(ctx, keyspace, shard) }) // tablet actions actionRepo.RegisterTabletAction("Ping", "", func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *pb.TabletAlias, r *http.Request) (string, error) { ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias) if err != nil { return "", err } return "", wr.TabletManagerClient().Ping(ctx, ti) }) actionRepo.RegisterTabletAction("RefreshState", acl.ADMIN, func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *pb.TabletAlias, r *http.Request) (string, error) { ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias) if err != nil { return "", err } return "", wr.TabletManagerClient().RefreshState(ctx, ti) }) actionRepo.RegisterTabletAction("DeleteTablet", acl.ADMIN, func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *pb.TabletAlias, r *http.Request) (string, error) { return "", wr.DeleteTablet(ctx, tabletAlias, false, false) }) actionRepo.RegisterTabletAction("ReloadSchema", acl.ADMIN, func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *pb.TabletAlias, r *http.Request) (string, error) { return "", wr.ReloadSchema(ctx, tabletAlias) }) // keyspace actions http.HandleFunc("/keyspace_actions", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpErrorf(w, r, "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 } ctx := context.Background() result := actionRepo.ApplyKeyspaceAction(ctx, 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 { httpErrorf(w, r, "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 } ctx := context.Background() result := actionRepo.ApplyShardAction(ctx, 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 { httpErrorf(w, r, "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 := topoproto.ParseTabletAlias(alias) if err != nil { http.Error(w, "bad alias provided", http.StatusBadRequest) return } ctx := context.Background() result := actionRepo.ApplyTabletAction(ctx, 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 { httpErrorf(w, r, "cannot parse form: %s", err) return } result := DbTopologyResult{} ctx := context.TODO() topology, err := topotools.DbTopology(ctx, ts) if err == nil && modifyDbTopology != nil { err = modifyDbTopology(ctx, ts, topology) } 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) { ctx := context.Background() parts := strings.Split(r.URL.Path, "/") cell := parts[len(parts)-1] if cell == "" { cells, err := ts.GetKnownCells(ctx) if err != nil { httpErrorf(w, r, "cannot get known cells: %v", err) return } templateLoader.ServeTemplate("serving_graph_cells.html", cells, w, r) return } servingGraph := topotools.DbServingGraph(ctx, ts, cell) if modifyDbServingGraph != nil { modifyDbServingGraph(ctx, ts, servingGraph) } templateLoader.ServeTemplate("serving_graph.html", servingGraph, w, r) }) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/app/", http.StatusFound) }) http.HandleFunc("/content/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, *templateDir+r.URL.Path[8:]) }) // Serve the static files for the vtctld web app. http.HandleFunc("/app/", func(w http.ResponseWriter, r *http.Request) { // Strip the prefix. parts := strings.SplitN(r.URL.Path, "/", 3) if len(parts) != 3 { http.NotFound(w, r) return } rest := parts[2] if rest == "" { rest = "index.html" } http.ServeFile(w, r, path.Join(*webDir, rest)) }) // Serve the REST API for the vtctld web app. initAPI(context.Background(), ts, actionRepo) // vschema viewer http.HandleFunc("/vschema", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpErrorf(w, r, "cannot parse form: %s", err) return } var data struct { Error error Input, Output string } ctx := context.Background() switch r.Method { case "POST": data.Input = r.FormValue("vschema") data.Error = ts.SaveVSchema(ctx, data.Input) } vschema, err := ts.GetVSchema(ctx) if err != nil { if data.Error == nil { data.Error = fmt.Errorf("Error fetching schema: %s", err) } } data.Output = vschema templateLoader.ServeTemplate("vschema.html", data, w, r) }) // redirects for explorers http.HandleFunc("/explorers/redirect", func(w http.ResponseWriter, r *http.Request) { if explorer == nil { http.Error(w, "no explorer configured", http.StatusInternalServerError) return } if err := r.ParseForm(); err != nil { httpErrorf(w, r, "cannot parse form: %s", err) return } target, err := handleExplorerRedirect(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } http.Redirect(w, r, target, http.StatusFound) }) // serve some data knownCellsCache := newKnownCellsCache(ts) http.HandleFunc("/json/KnownCells", func(w http.ResponseWriter, r *http.Request) { ctx := context.Background() result, err := knownCellsCache.Get(ctx) if err != nil { httpErrorf(w, r, "error getting known cells: %v", err) return } w.Write(result) }) keyspacesCache := newKeyspacesCache(ts) http.HandleFunc("/json/Keyspaces", func(w http.ResponseWriter, r *http.Request) { ctx := context.Background() result, err := keyspacesCache.Get(ctx) if err != nil { httpErrorf(w, r, "error getting keyspaces: %v", err) return } w.Write(result) }) keyspaceCache := newKeyspaceCache(ts) http.HandleFunc("/json/Keyspace", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpErrorf(w, r, "cannot parse form: %s", err) return } keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "no keyspace provided", http.StatusBadRequest) return } ctx := context.Background() result, err := keyspaceCache.Get(ctx, keyspace) if err != nil { httpErrorf(w, r, "error getting keyspace: %v", err) return } w.Write(result) }) shardNamesCache := newShardNamesCache(ts) http.HandleFunc("/json/ShardNames", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpErrorf(w, r, "cannot parse form: %s", err) return } keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "no keyspace provided", http.StatusBadRequest) return } ctx := context.Background() result, err := shardNamesCache.Get(ctx, keyspace) if err != nil { httpErrorf(w, r, "error getting shardNames: %v", err) return } w.Write(result) }) shardCache := newShardCache(ts) http.HandleFunc("/json/Shard", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpErrorf(w, r, "cannot parse form: %s", err) 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 } ctx := context.Background() result, err := shardCache.Get(ctx, keyspace+"/"+shard) if err != nil { httpErrorf(w, r, "error getting shard: %v", err) return } w.Write(result) }) cellShardTabletsCache := newCellShardTabletsCache(ts) http.HandleFunc("/json/CellShardTablets", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpErrorf(w, r, "cannot parse form: %s", err) return } cell := r.FormValue("cell") if cell == "" { http.Error(w, "no cell 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 } ctx := context.Background() result, err := cellShardTabletsCache.Get(ctx, cell+"/"+keyspace+"/"+shard) if err != nil { httpErrorf(w, r, "error getting shard: %v", err) return } w.Write(result) }) // flush all data and will force a full client reload http.HandleFunc("/json/flush", func(w http.ResponseWriter, r *http.Request) { knownCellsCache.Flush() keyspacesCache.Flush() keyspaceCache.Flush() shardNamesCache.Flush() shardCache.Flush() cellShardTabletsCache.Flush() }) http.HandleFunc("/json/schema-manager", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { httpErrorf(w, r, "cannot parse form: %s", err) return } sqlStr := r.FormValue("data") keyspace := r.FormValue("keyspace") executor := schemamanager.NewTabletExecutor( tmclient.NewTabletManagerClient(), ts) ctx := context.Background() schemamanager.Run( ctx, schemamanager.NewUIController(sqlStr, keyspace, w), executor, ) }) if *schemaChangeDir != "" { interval := 60 if *schemaChangeCheckInterval > 0 { interval = *schemaChangeCheckInterval } timer := timer.NewTimer(time.Duration(interval) * time.Second) controllerFactory, err := schemamanager.GetControllerFactory(*schemaChangeController) if err != nil { log.Fatalf("unable to get a controller factory, error: %v", err) } timer.Start(func() { controller, err := controllerFactory(map[string]string{ schemamanager.SchemaChangeDirName: *schemaChangeDir, schemamanager.SchemaChangeUser: *schemaChangeUser, }) if err != nil { log.Errorf("failed to get controller, error: %v", err) return } ctx := context.Background() err = schemamanager.Run( ctx, controller, schemamanager.NewTabletExecutor( tmclient.NewTabletManagerClient(), ts), ) if err != nil { log.Errorf("Schema change failed, error: %v", err) } }) servenv.OnClose(func() { timer.Stop() }) } servenv.RunDefault() }
func main() { flag.Parse() servenv.Init() defer servenv.Close() templateLoader = NewTemplateLoader(*templateDir, dummyTemplate, *debug) ts := topo.GetServer() defer topo.CloseServers() wr := wrangler.New(ts, 30*time.Second, 30*time.Second) actionRepo = NewActionRepository(wr) // 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, 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, 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("RpcPing", func(wr *wrangler.Wrangler, tabletAlias topo.TabletAlias, r *http.Request) (string, error) { return "", wr.ActionInitiator().RpcPing(tabletAlias, 10*time.Second) }) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { templateLoader.ServeTemplate("index.html", indexContent, w, r) }) 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) }) 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) }) 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) }) 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 := wr.DbTopology() if err != nil { result.Error = err.Error() } else { result.Topology = topology } templateLoader.ServeTemplate("dbtopo.html", result, w, r) }) 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 := wr.TopoServer().GetKnownCells() if err != nil { httpError(w, "cannot get known cells: %v", err) return } else { templateLoader.ServeTemplate("serving_graph_cells.html", cells, w, r) } return } result := ServingGraphResult{} servingGraph, err := wr.ServingGraph(cell) if err != nil { result.Error = err.Error() } else { result.ServingGraph = servingGraph } templateLoader.ServeTemplate("serving_graph.html", result, w, r) }) 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 } explorerName := r.FormValue("explorer") 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": keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } cell := r.FormValue("cell") if cell == "" { http.Error(w, "cell is obligatory for this redirect", http.StatusBadRequest) return } target = explorer.GetSrvKeyspacePath(cell, keyspace) case "srv_shard": keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } cell := r.FormValue("cell") if cell == "" { http.Error(w, "cell 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": keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } cell := r.FormValue("cell") if cell == "" { http.Error(w, "cell 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": keyspace := r.FormValue("keyspace") if keyspace == "" { http.Error(w, "keyspace is obligatory for this redirect", http.StatusBadRequest) return } cell := r.FormValue("cell") if cell == "" { http.Error(w, "cell 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.Run(*port) }
func main() { flag.Parse() servenv.Init() defer servenv.Close() templateLoader = NewTemplateLoader(*templateDir, dummyTemplate, *debug) ts := topo.GetServer() defer topo.CloseServers() wr := wrangler.New(ts, 30*time.Second, 30*time.Second) actionRepo = NewActionRepository(wr) // 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, 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, 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("RpcPing", func(wr *wrangler.Wrangler, tabletAlias topo.TabletAlias, r *http.Request) (string, error) { return "", wr.ActionInitiator().RpcPing(tabletAlias, 10*time.Second) }) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { templateLoader.ServeTemplate("index.html", indexContent, w, r) }) 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) }) 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) }) 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) }) 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 := wr.DbTopology() if err != nil { result.Error = err.Error() } else { result.Topology = topology } templateLoader.ServeTemplate("dbtopo.html", result, w, r) }) servenv.Run(*port) }
func main() { defer exit.Recover() defer logutil.Flush() dbconfigFlags := dbconfigs.AppConfig | dbconfigs.DbaConfig | dbconfigs.FilteredConfig | dbconfigs.ReplConfig dbconfigs.RegisterFlags(dbconfigFlags) flag.Parse() // We'll register this OnTerm handler before mysqld starts, so we get notified // if mysqld dies on its own without us (or our RPC client) telling it to. mysqldTerminated := make(chan struct{}) onTermFunc := func() { close(mysqldTerminated) } // Start or Init mysqld as needed. ctx, cancel := context.WithTimeout(context.Background(), *waitTime) tabletDir := mysqlctl.TabletDir(uint32(*tabletUID)) if _, statErr := os.Stat(tabletDir); os.IsNotExist(statErr) { // Generate my.cnf from scratch and use it to find mysqld. log.Infof("tablet dir (%s) doesn't exist, initializing", tabletDir) var err error mysqld, err = mysqlctl.CreateMysqld(uint32(*tabletUID), *mysqlSocket, int32(*mysqlPort), dbconfigFlags) if err != nil { log.Errorf("failed to initialize mysql config: %v", err) exit.Return(1) } mysqld.OnTerm(onTermFunc) if err := mysqld.Init(ctx, *initDBSQLFile); err != nil { log.Errorf("failed to initialize mysql data dir and start mysqld: %v", err) exit.Return(1) } } else { // There ought to be an existing my.cnf, so use it to find mysqld. log.Infof("tablet dir (%s) already exists, starting without init", tabletDir) var err error mysqld, err = mysqlctl.OpenMysqld(uint32(*tabletUID), dbconfigFlags) if err != nil { log.Errorf("failed to find mysql config: %v", err) exit.Return(1) } mysqld.OnTerm(onTermFunc) if err := mysqld.Start(ctx); err != nil { log.Errorf("failed to start mysqld: %v", err) exit.Return(1) } } cancel() servenv.Init() defer servenv.Close() // Take mysqld down with us on SIGTERM before entering lame duck. servenv.OnTerm(func() { log.Infof("mysqlctl received SIGTERM, shutting down mysqld first") ctx := context.Background() mysqld.Shutdown(ctx, false) }) // Start RPC server and wait for SIGTERM. mysqlctldTerminated := make(chan struct{}) go func() { servenv.RunDefault() close(mysqlctldTerminated) }() select { case <-mysqldTerminated: log.Infof("mysqld shut down on its own, exiting mysqlctld") case <-mysqlctldTerminated: log.Infof("mysqlctld shut down gracefully") } }
func main() { dbConfigsFile, dbCredentialsFile := dbconfigs.RegisterCommonFlags() flag.Parse() servenv.Init() defer servenv.Close() tabletAlias := vttablet.TabletParamToTabletAlias(*tabletPath) if *mycnfFile == "" { *mycnfFile = mysqlctl.MycnfFile(tabletAlias.Uid) } mycnf, err := mysqlctl.ReadMycnf(*mycnfFile) if err != nil { log.Fatalf("mycnf read failed: %v", err) } dbcfgs, err := dbconfigs.Init(mycnf.SocketFile, *dbConfigsFile, *dbCredentialsFile) if err != nil { log.Warning(err) } ts.InitQueryService() mysqlctl.RegisterUpdateStreamService(mycnf) // Depends on both query and updateStream. ts.RegisterCacheInvalidator() // Depends on both query and updateStream. if err := vttablet.InitAgent(tabletAlias, dbcfgs, mycnf, *dbConfigsFile, *dbCredentialsFile, *port, *securePort, *mycnfFile, *overridesFile); err != nil { log.Fatal(err) } servenv.ServeRPC() vttablet.HttpHandleSnapshots(mycnf, tabletAlias.Uid) l, err := proc.Listen(fmt.Sprintf("%v", *port)) if err != nil { log.Fatal(err) } go http.Serve(l, nil) if *securePort != 0 { log.Infof("listening on secure port %v", *securePort) vttablet.SecureServe(fmt.Sprintf(":%d", *securePort), *cert, *key, *caCert) } log.Infof("started vttablet %v", *port) s := proc.Wait() // A SIGUSR1 means that we're restarting if s == syscall.SIGUSR1 { // Give some time for the other process // to pick up the listeners log.Info("Exiting on SIGUSR1") time.Sleep(5 * time.Millisecond) ts.DisallowQueries(true) } else { log.Info("Exiting on SIGTERM") ts.DisallowQueries(false) } mysqlctl.DisableUpdateStreamService() topo.CloseServers() vttablet.CloseAgent() }
func main() { defer exit.Recover() defer logutil.Flush() flags := dbconfigs.AppConfig | dbconfigs.DbaConfig | dbconfigs.FilteredConfig | dbconfigs.ReplConfig dbconfigs.RegisterFlags(flags) flag.Parse() mycnf := mysqlctl.NewMycnf(uint32(*tabletUID), int32(*mysqlPort)) if *mysqlSocket != "" { mycnf.SocketFile = *mysqlSocket } dbcfgs, err := dbconfigs.Init(mycnf.SocketFile, flags) if err != nil { log.Errorf("%v", err) exit.Return(255) } mysqld = mysqlctl.NewMysqld("Dba", "App", mycnf, &dbcfgs.Dba, &dbcfgs.App.ConnParams, &dbcfgs.Repl) // Register OnTerm handler before mysqld starts, so we get notified if mysqld // dies on its own without us (or our RPC client) telling it to. mysqldTerminated := make(chan struct{}) mysqld.OnTerm(func() { close(mysqldTerminated) }) // Start or Init mysqld as needed. ctx, cancel := context.WithTimeout(context.Background(), *waitTime) if _, err = os.Stat(mycnf.DataDir); os.IsNotExist(err) { log.Infof("mysql data dir (%s) doesn't exist, initializing", mycnf.DataDir) mysqld.Init(ctx, *initDBSQLFile) } else { log.Infof("mysql data dir (%s) already exists, starting without init", mycnf.DataDir) mysqld.Start(ctx) } cancel() servenv.Init() defer servenv.Close() // Take mysqld down with us on SIGTERM before entering lame duck. servenv.OnTerm(func() { log.Infof("mysqlctl received SIGTERM, shutting down mysqld first") ctx := context.Background() mysqld.Shutdown(ctx, false) }) // Start RPC server and wait for SIGTERM. mysqlctldTerminated := make(chan struct{}) go func() { servenv.RunDefault() close(mysqlctldTerminated) }() select { case <-mysqldTerminated: log.Infof("mysqld shut down on its own, exiting mysqlctld") case <-mysqlctldTerminated: log.Infof("mysqlctld shut down gracefully") } }
func main() { flag.Parse() servenv.Init() defer servenv.Close() ts = topo.GetServer() defer topo.CloseServers() actionRepo = NewActionRepository(ts) // keyspace actions actionRepo.RegisterKeyspaceAction("ValidateKeyspace", func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateKeyspace(ctx, keyspace, false) }) actionRepo.RegisterKeyspaceAction("ValidateSchemaKeyspace", func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateSchemaKeyspace(ctx, keyspace, nil, false) }) actionRepo.RegisterKeyspaceAction("ValidateVersionKeyspace", func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidateVersionKeyspace(ctx, keyspace) }) actionRepo.RegisterKeyspaceAction("ValidatePermissionsKeyspace", func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) { return "", wr.ValidatePermissionsKeyspace(ctx, keyspace) }) // shard actions actionRepo.RegisterShardAction("ValidateShard", func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateShard(ctx, keyspace, shard, false) }) actionRepo.RegisterShardAction("ValidateSchemaShard", func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateSchemaShard(ctx, keyspace, shard, nil, false) }) actionRepo.RegisterShardAction("ValidateVersionShard", func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidateVersionShard(ctx, keyspace, shard) }) actionRepo.RegisterShardAction("ValidatePermissionsShard", func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) { return "", wr.ValidatePermissionsShard(ctx, keyspace, shard) }) // tablet actions actionRepo.RegisterTabletAction("Ping", "", func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) { ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias) if err != nil { return "", err } return "", wr.TabletManagerClient().Ping(ctx, ti) }) actionRepo.RegisterTabletAction("RefreshState", acl.ADMIN, func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) { ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias) if err != nil { return "", err } return "", wr.TabletManagerClient().RefreshState(ctx, ti) }) actionRepo.RegisterTabletAction("DeleteTablet", acl.ADMIN, func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) { return "", wr.DeleteTablet(ctx, tabletAlias, false, false) }) actionRepo.RegisterTabletAction("ReloadSchema", acl.ADMIN, func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) { return "", wr.ReloadSchema(ctx, tabletAlias) }) // Anything unrecognized gets redirected to the main app page. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, appPrefix, http.StatusFound) }) // Serve the static files for the vtctld web app. http.HandleFunc(appPrefix, func(w http.ResponseWriter, r *http.Request) { // Strip the prefix. parts := strings.SplitN(r.URL.Path, "/", 3) if len(parts) != 3 { http.NotFound(w, r) return } rest := parts[2] if rest == "" { rest = "index.html" } http.ServeFile(w, r, path.Join(*webDir, rest)) }) // Serve the REST API for the vtctld web app. initAPI(context.Background(), ts, actionRepo) // redirects for explorers http.HandleFunc("/explorers/redirect", func(w http.ResponseWriter, r *http.Request) { if explorer == nil { http.Error(w, "no explorer configured", http.StatusInternalServerError) return } if err := r.ParseForm(); err != nil { httpErrorf(w, r, "cannot parse form: %s", err) return } target, err := handleExplorerRedirect(context.Background(), ts, r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } http.Redirect(w, r, target, http.StatusFound) }) // Start schema manager service. if *schemaChangeDir != "" { interval := 60 if *schemaChangeCheckInterval > 0 { interval = *schemaChangeCheckInterval } timer := timer.NewTimer(time.Duration(interval) * time.Second) controllerFactory, err := schemamanager.GetControllerFactory(*schemaChangeController) if err != nil { log.Fatalf("unable to get a controller factory, error: %v", err) } timer.Start(func() { controller, err := controllerFactory(map[string]string{ schemamanager.SchemaChangeDirName: *schemaChangeDir, schemamanager.SchemaChangeUser: *schemaChangeUser, }) if err != nil { log.Errorf("failed to get controller, error: %v", err) return } ctx := context.Background() err = schemamanager.Run( ctx, controller, schemamanager.NewTabletExecutor( tmclient.NewTabletManagerClient(), ts), ) if err != nil { log.Errorf("Schema change failed, error: %v", err) } }) servenv.OnClose(func() { timer.Stop() }) } servenv.RunDefault() }