// NewComboActionAgent creates an agent tailored specifically to run // within the vtcombo binary. It cannot be called concurrently, // as it changes the flags. func NewComboActionAgent(batchCtx context.Context, ts topo.Server, tabletAlias *pb.TabletAlias, vtPort, grpcPort int32, queryServiceControl tabletserver.Controller, dbcfgs dbconfigs.DBConfigs, mysqlDaemon mysqlctl.MysqlDaemon, keyspace, shard, dbname, tabletType string) *ActionAgent { agent := &ActionAgent{ QueryServiceControl: queryServiceControl, UpdateStream: binlog.NewUpdateStreamControlMock(), HealthReporter: health.DefaultAggregator, batchCtx: batchCtx, TopoServer: ts, TabletAlias: tabletAlias, MysqlDaemon: mysqlDaemon, DBConfigs: dbcfgs, SchemaOverrides: nil, BinlogPlayerMap: nil, History: history.New(historyLength), lastHealthMapCount: new(stats.Int), _healthy: fmt.Errorf("healthcheck not run yet"), } agent.registerQueryRuleSources() // initialize the tablet *initDbNameOverride = dbname *initKeyspace = keyspace *initShard = shard *initTabletType = tabletType if err := agent.InitTablet(vtPort, grpcPort); err != nil { panic(fmt.Errorf("agent.InitTablet failed: %v", err)) } // and start the agent if err := agent.Start(batchCtx, 0, vtPort, grpcPort, false); err != nil { panic(fmt.Errorf("agent.Start(%v) failed: %v", tabletAlias, err)) } return agent }
// NewTabletServer creates an instance of TabletServer. Only one instance // of TabletServer can be created per process. func NewTabletServer(config Config) *TabletServer { tsv := &TabletServer{ config: config, QueryTimeout: sync2.NewAtomicDuration(time.Duration(config.QueryTimeout * 1e9)), BeginTimeout: sync2.NewAtomicDuration(time.Duration(config.TxPoolTimeout * 1e9)), checkMySQLThrottler: sync2.NewSemaphore(1, 0), streamHealthMap: make(map[int]chan<- *querypb.StreamHealthResponse), sessionID: Rand(), history: history.New(10), } tsv.qe = NewQueryEngine(tsv, config) tsv.invalidator = NewRowcacheInvalidator(config.StatsPrefix, tsv, tsv.qe, config.EnablePublishStats) if config.EnablePublishStats { stats.Publish(config.StatsPrefix+"TabletState", stats.IntFunc(func() int64 { tsv.mu.Lock() state := tsv.state tsv.mu.Unlock() return state })) stats.Publish(config.StatsPrefix+"QueryTimeout", stats.DurationFunc(tsv.QueryTimeout.Get)) stats.Publish(config.StatsPrefix+"BeginTimeout", stats.DurationFunc(tsv.BeginTimeout.Get)) stats.Publish(config.StatsPrefix+"TabletStateName", stats.StringFunc(tsv.GetState)) } return tsv }
// NewTestActionAgent creates an agent for test purposes. Only a // subset of features are supported now, but we'll add more over time. func NewTestActionAgent(batchCtx context.Context, ts topo.Server, tabletAlias *topodatapb.TabletAlias, vtPort, grpcPort int32, mysqlDaemon mysqlctl.MysqlDaemon, preStart func(*ActionAgent)) *ActionAgent { agent := &ActionAgent{ QueryServiceControl: tabletservermock.NewController(), UpdateStream: binlog.NewUpdateStreamControlMock(), HealthReporter: health.DefaultAggregator, batchCtx: batchCtx, TopoServer: ts, TabletAlias: tabletAlias, MysqlDaemon: mysqlDaemon, DBConfigs: dbconfigs.DBConfigs{}, BinlogPlayerMap: nil, History: history.New(historyLength), _healthy: fmt.Errorf("healthcheck not run yet"), } if preStart != nil { preStart(agent) } // Start will update the topology and setup services. if err := agent.Start(batchCtx, 0, vtPort, grpcPort, false); err != nil { panic(fmt.Errorf("agent.Start(%v) failed: %v", tabletAlias, err)) } // Update our running state. if err := agent.refreshTablet(batchCtx, "Start"); err != nil { panic(fmt.Errorf("agent.refreshTablet(%v) failed: %v", tabletAlias, err)) } return agent }
// NewActionAgent creates a new ActionAgent and registers all the // associated services func NewActionAgent( tabletAlias topo.TabletAlias, dbcfgs *dbconfigs.DBConfigs, mycnf *mysqlctl.Mycnf, port, securePort int, overridesFile string, lockTimeout time.Duration, ) (agent *ActionAgent, err error) { schemaOverrides := loadSchemaOverrides(overridesFile) topoServer := topo.GetServer() mysqld := mysqlctl.NewMysqld("Dba", mycnf, &dbcfgs.Dba, &dbcfgs.Repl) agent = &ActionAgent{ TopoServer: topoServer, TabletAlias: tabletAlias, Mysqld: mysqld, MysqlDaemon: mysqld, DBConfigs: dbcfgs, SchemaOverrides: schemaOverrides, LockTimeout: lockTimeout, done: make(chan struct{}), History: history.New(historyLength), lastHealthMapCount: stats.NewInt("LastHealthMapCount"), changeItems: make(chan tabletChangeItem, 100), } // Start the binlog player services, not playing at start. agent.BinlogPlayerMap = NewBinlogPlayerMap(topoServer, &dbcfgs.Filtered, mysqld) RegisterBinlogPlayerMap(agent.BinlogPlayerMap) // try to figure out the mysql port mysqlPort := mycnf.MysqlPort if mysqlPort == 0 { // we don't know the port, try to get it from mysqld var err error mysqlPort, err = mysqld.GetMysqlPort() if err != nil { log.Warningf("Cannot get current mysql port, will use 0 for now: %v", err) } } if err := agent.Start(mysqlPort, port, securePort); err != nil { return nil, err } // register the RPC services from the agent agent.registerQueryService() // start health check if needed agent.initHeathCheck() return agent, nil }
// NewTestActionAgent creates an agent for test purposes. Only a // subset of features are supported now, but we'll add more over time. func NewTestActionAgent(ts topo.Server, tabletAlias topo.TabletAlias, port int, mysqlDaemon mysqlctl.MysqlDaemon) (agent *ActionAgent) { agent = &ActionAgent{ TopoServer: ts, TabletAlias: tabletAlias, Mysqld: nil, MysqlDaemon: mysqlDaemon, DBConfigs: nil, SchemaOverrides: nil, BinlogPlayerMap: nil, done: make(chan struct{}), History: history.New(historyLength), lastHealthMapCount: new(stats.Int), } if err := agent.Start(0, port, 0); err != nil { panic(fmt.Errorf("agent.Start(%v) failed: %v", tabletAlias, err)) } return agent }
// NewTestActionAgent creates an agent for test purposes. Only a // subset of features are supported now, but we'll add more over time. func NewTestActionAgent(batchCtx context.Context, ts topo.Server, tabletAlias topo.TabletAlias, vtPort, grpcPort int, mysqlDaemon mysqlctl.MysqlDaemon) *ActionAgent { agent := &ActionAgent{ QueryServiceControl: tabletserver.NewTestQueryServiceControl(), HealthReporter: health.DefaultAggregator, batchCtx: batchCtx, TopoServer: ts, TabletAlias: tabletAlias, MysqlDaemon: mysqlDaemon, DBConfigs: nil, SchemaOverrides: nil, BinlogPlayerMap: nil, History: history.New(historyLength), lastHealthMapCount: new(stats.Int), _healthy: fmt.Errorf("healthcheck not run yet"), } if err := agent.Start(batchCtx, 0, vtPort, 0, grpcPort); err != nil { panic(fmt.Errorf("agent.Start(%v) failed: %v", tabletAlias, err)) } return agent }
// NewActionAgent creates a new ActionAgent and registers all the // associated services func NewActionAgent( tabletAlias topo.TabletAlias, dbcfgs *dbconfigs.DBConfigs, mycnf *mysqlctl.Mycnf, port, securePort int, overridesFile string, ) (agent *ActionAgent, err error) { schemaOverrides := loadSchemaOverrides(overridesFile) topoServer := topo.GetServer() mysqld := mysqlctl.NewMysqld(mycnf, &dbcfgs.Dba, &dbcfgs.Repl) agent = &ActionAgent{ TopoServer: topoServer, TabletAlias: tabletAlias, Mysqld: mysqld, DBConfigs: dbcfgs, SchemaOverrides: schemaOverrides, done: make(chan struct{}), History: history.New(historyLength), changeItems: make(chan tabletChangeItem, 100), } // Start the binlog player services, not playing at start. agent.BinlogPlayerMap = NewBinlogPlayerMap(topoServer, &dbcfgs.App.ConnectionParams, mysqld) RegisterBinlogPlayerMap(agent.BinlogPlayerMap) if err := agent.Start(mysqld.Port(), port, securePort); err != nil { return nil, err } // register the RPC services from the agent agent.registerQueryService() // start health check if needed agent.initHeathCheck() return agent, nil }
// NewActionAgent creates a new ActionAgent and registers all the // associated services. // // batchCtx is the context that the agent will use for any background tasks // it spawns. func NewActionAgent( batchCtx context.Context, mysqld mysqlctl.MysqlDaemon, queryServiceControl tabletserver.QueryServiceControl, tabletAlias topo.TabletAlias, dbcfgs *dbconfigs.DBConfigs, mycnf *mysqlctl.Mycnf, port, securePort, gRPCPort int, overridesFile string, lockTimeout time.Duration, ) (agent *ActionAgent, err error) { schemaOverrides := loadSchemaOverrides(overridesFile) topoServer := topo.GetServer() agent = &ActionAgent{ QueryServiceControl: queryServiceControl, HealthReporter: health.DefaultAggregator, batchCtx: batchCtx, TopoServer: topoServer, TabletAlias: tabletAlias, MysqlDaemon: mysqld, DBConfigs: dbcfgs, SchemaOverrides: schemaOverrides, LockTimeout: lockTimeout, History: history.New(historyLength), lastHealthMapCount: stats.NewInt("LastHealthMapCount"), _healthy: fmt.Errorf("healthcheck not run yet"), healthStreamMap: make(map[int]chan<- *actionnode.HealthStreamReply), } // try to initialize the tablet if we have to if err := agent.InitTablet(port, securePort, gRPCPort); err != nil { return nil, fmt.Errorf("agent.InitTablet failed: %v", err) } // Publish and set the TargetTabletType. Not a global var // since it should never be changed. statsTabletType := stats.NewString("TargetTabletType") statsTabletType.Set(*targetTabletType) // Start the binlog player services, not playing at start. agent.BinlogPlayerMap = NewBinlogPlayerMap(topoServer, &dbcfgs.Filtered, mysqld) RegisterBinlogPlayerMap(agent.BinlogPlayerMap) // try to figure out the mysql port mysqlPort := mycnf.MysqlPort if mysqlPort == 0 { // we don't know the port, try to get it from mysqld var err error mysqlPort, err = mysqld.GetMysqlPort() if err != nil { log.Warningf("Cannot get current mysql port, will use 0 for now: %v", err) } } if err := agent.Start(batchCtx, mysqlPort, port, securePort, gRPCPort); err != nil { return nil, err } // register the RPC services from the agent agent.registerQueryService() // two cases then: // - restoreFromBackup is set: we restore, then initHealthCheck, all // in the background // - restoreFromBackup is not set: we initHealthCheck right away if *restoreFromBackup { go func() { // restoreFromBackup wil just be a regular action // (same as if it was triggered remotely) if err := agent.RestoreFromBackup(batchCtx); err != nil { println(fmt.Sprintf("RestoreFromBackup failed: %v", err)) log.Fatalf("RestoreFromBackup failed: %v", err) } // after the restore is done, start health check agent.initHeathCheck() }() } else { // synchronously start health check if needed agent.initHeathCheck() } return agent, nil }
// TestInitTablet will test the InitTablet code creates / updates the // tablet node correctly. Note we modify global parameters (the flags) // so this has to be in one test. func TestInitTablet(t *testing.T) { ctx := context.Background() db := fakesqldb.Register() ts := zktopo.NewTestServer(t, []string{"cell1", "cell2"}) tabletAlias := &pb.TabletAlias{ Cell: "cell1", Uid: 1, } // start with idle, and a tablet record that doesn't exist port := int32(1234) gRPCPort := int32(3456) mysqlDaemon := mysqlctl.NewFakeMysqlDaemon(db) agent := &ActionAgent{ TopoServer: ts, TabletAlias: tabletAlias, MysqlDaemon: mysqlDaemon, DBConfigs: dbconfigs.DBConfigs{}, SchemaOverrides: nil, BinlogPlayerMap: nil, LockTimeout: 10 * time.Second, batchCtx: ctx, History: history.New(historyLength), lastHealthMapCount: new(stats.Int), _healthy: fmt.Errorf("healthcheck not run yet"), } *initTabletType = "idle" *tabletHostname = "localhost" if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("NewTestActionAgent(idle) failed: %v", err) } ti, err := ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != pb.TabletType_IDLE { t.Errorf("wrong type for tablet: %v", ti.Type) } if ti.Hostname != "localhost" { t.Errorf("wrong hostname for tablet: %v", ti.Hostname) } if ti.PortMap["vt"] != port { t.Errorf("wrong port for tablet: %v", ti.PortMap["vt"]) } if ti.PortMap["grpc"] != gRPCPort { t.Errorf("wrong gRPC port for tablet: %v", ti.PortMap["grpc"]) } // try again now that the node exists port = 3456 if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("NewTestActionAgent(idle again) failed: %v", err) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.PortMap["vt"] != port { t.Errorf("wrong port for tablet: %v", ti.PortMap["vt"]) } if ti.PortMap["grpc"] != gRPCPort { t.Errorf("wrong gRPC port for tablet: %v", ti.PortMap["grpc"]) } // try with a keyspace and shard on the previously idle tablet, // should fail *initTabletType = "replica" *initKeyspace = "test_keyspace" *initShard = "-80" if err := agent.InitTablet(port, gRPCPort); err == nil || !strings.Contains(err.Error(), "InitTablet failed because existing tablet keyspace and shard / differ from the provided ones test_keyspace/-80") { t.Fatalf("InitTablet(type over idle) didn't fail correctly: %v", err) } // now let's use a different real tablet in a shard, that will create // the keyspace and shard. tabletAlias = &pb.TabletAlias{ Cell: "cell1", Uid: 2, } agent.TabletAlias = tabletAlias if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type) failed: %v", err) } si, err := ts.GetShard(ctx, "test_keyspace", "-80") if err != nil { t.Fatalf("GetShard failed: %v", err) } if len(si.Cells) != 1 || si.Cells[0] != "cell1" { t.Errorf("shard.Cells not updated properly: %v", si) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != pb.TabletType_REPLICA { t.Errorf("wrong tablet type: %v", ti.Type) } // try to init again, this time with health check on *initTabletType = "" *targetTabletType = "replica" if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type, healthcheck) failed: %v", err) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != pb.TabletType_SPARE { t.Errorf("wrong tablet type: %v", ti.Type) } // update shard's master to our alias, then try to init again si, err = ts.GetShard(ctx, "test_keyspace", "-80") if err != nil { t.Fatalf("GetShard failed: %v", err) } si.MasterAlias = tabletAlias if err := ts.UpdateShard(ctx, si); err != nil { t.Fatalf("UpdateShard failed: %v", err) } if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type, healthcheck) failed: %v", err) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != pb.TabletType_MASTER { t.Errorf("wrong tablet type: %v", ti.Type) } // init again with the tablet_type set, no healthcheck // (also check db name override and tags here) *initTabletType = "replica" *targetTabletType = "" *initDbNameOverride = "DBNAME" initTags.Set("aaa:bbb") if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type, healthcheck) failed: %v", err) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != pb.TabletType_MASTER { t.Errorf("wrong tablet type: %v", ti.Type) } if ti.DbNameOverride != "DBNAME" { t.Errorf("wrong tablet DbNameOverride: %v", ti.DbNameOverride) } if len(ti.Tags) != 1 || ti.Tags["aaa"] != "bbb" { t.Errorf("wrong tablet tags: %v", ti.Tags) } }
// NewActionAgent creates a new ActionAgent and registers all the // associated services. // // batchCtx is the context that the agent will use for any background tasks // it spawns. func NewActionAgent( batchCtx context.Context, mysqld mysqlctl.MysqlDaemon, queryServiceControl tabletserver.Controller, tabletAlias *topodatapb.TabletAlias, dbcfgs dbconfigs.DBConfigs, mycnf *mysqlctl.Mycnf, port, gRPCPort int32, overridesFile string, ) (agent *ActionAgent, err error) { schemaOverrides := loadSchemaOverrides(overridesFile) topoServer := topo.GetServer() agent = &ActionAgent{ QueryServiceControl: queryServiceControl, HealthReporter: health.DefaultAggregator, batchCtx: batchCtx, TopoServer: topoServer, TabletAlias: tabletAlias, MysqlDaemon: mysqld, DBConfigs: dbcfgs, SchemaOverrides: schemaOverrides, History: history.New(historyLength), lastHealthMapCount: stats.NewInt("LastHealthMapCount"), _healthy: fmt.Errorf("healthcheck not run yet"), } agent.registerQueryRuleSources() // try to initialize the tablet if we have to if err := agent.InitTablet(port, gRPCPort); err != nil { return nil, fmt.Errorf("agent.InitTablet failed: %v", err) } // Publish and set the TargetTabletType. Not a global var // since it should never be changed. statsTabletType := stats.NewString("TargetTabletType") statsTabletType.Set(*targetTabletType) // Create the TabletType stats agent.exportStats = true agent.statsTabletType = stats.NewString("TabletType") // Start the binlog player services, not playing at start. agent.BinlogPlayerMap = NewBinlogPlayerMap(topoServer, mysqld, func() binlogplayer.VtClient { return binlogplayer.NewDbClient(&agent.DBConfigs.Filtered) }) // Stop all binlog players upon entering lameduck. servenv.OnTerm(agent.BinlogPlayerMap.StopAllPlayersAndReset) RegisterBinlogPlayerMap(agent.BinlogPlayerMap) // try to figure out the mysql port mysqlPort := mycnf.MysqlPort if mysqlPort == 0 { // we don't know the port, try to get it from mysqld var err error mysqlPort, err = mysqld.GetMysqlPort() if err != nil { log.Warningf("Cannot get current mysql port, will use 0 for now: %v", err) } } // Start will get the tablet info, and update our state from it if err := agent.Start(batchCtx, int32(mysqlPort), port, gRPCPort, true); err != nil { return nil, err } // register the RPC services from the agent agent.registerQueryService() // two cases then: // - restoreFromBackup is set: we restore, then initHealthCheck, all // in the background // - restoreFromBackup is not set: we initHealthCheck right away if *restoreFromBackup { go func() { // restoreFromBackup wil just be a regular action // (same as if it was triggered remotely) if err := agent.RestoreFromBackup(batchCtx); err != nil { println(fmt.Sprintf("RestoreFromBackup failed: %v", err)) log.Fatalf("RestoreFromBackup failed: %v", err) } // after the restore is done, start health check agent.initHealthCheck() }() } else { // synchronously start health check if needed agent.initHealthCheck() } return agent, nil }
func NewAggregator() *Aggregator { return &Aggregator{ History: history.New(historyLength), reporters: make(map[string]Reporter), } }
// NewActionAgent creates a new ActionAgent and registers all the // associated services. // // batchCtx is the context that the agent will use for any background tasks // it spawns. func NewActionAgent( batchCtx context.Context, mysqld mysqlctl.MysqlDaemon, queryServiceControl tabletserver.Controller, tabletAlias *topodatapb.TabletAlias, dbcfgs dbconfigs.DBConfigs, mycnf *mysqlctl.Mycnf, port, gRPCPort int32, ) (agent *ActionAgent, err error) { topoServer := topo.GetServer() orc, err := newOrcClient() if err != nil { return nil, err } agent = &ActionAgent{ QueryServiceControl: queryServiceControl, HealthReporter: health.DefaultAggregator, batchCtx: batchCtx, TopoServer: topoServer, TabletAlias: tabletAlias, MysqlDaemon: mysqld, DBConfigs: dbcfgs, History: history.New(historyLength), _healthy: fmt.Errorf("healthcheck not run yet"), orc: orc, } agent.registerQueryRuleSources() // try to initialize the tablet if we have to if err := agent.InitTablet(port, gRPCPort); err != nil { return nil, fmt.Errorf("agent.InitTablet failed: %v", err) } // Create the TabletType stats agent.exportStats = true agent.statsTabletType = stats.NewString("TabletType") // Start the binlog player services, not playing at start. agent.BinlogPlayerMap = NewBinlogPlayerMap(topoServer, mysqld, func() binlogplayer.VtClient { return binlogplayer.NewDbClient(&agent.DBConfigs.Filtered) }) // Stop all binlog players upon entering lameduck. servenv.OnTerm(agent.BinlogPlayerMap.StopAllPlayersAndReset) RegisterBinlogPlayerMap(agent.BinlogPlayerMap) // try to figure out the mysql port mysqlPort := mycnf.MysqlPort if mysqlPort == 0 { // we don't know the port, try to get it from mysqld var err error mysqlPort, err = mysqld.GetMysqlPort() if err != nil { log.Warningf("Cannot get current mysql port, will use 0 for now: %v", err) } } // Start will get the tablet info, and update our state from it if err := agent.Start(batchCtx, int32(mysqlPort), port, gRPCPort, true); err != nil { return nil, err } // register the RPC services from the agent servenv.OnRun(func() { agent.registerQueryService() }) // two cases then: // - restoreFromBackup is set: we restore, then initHealthCheck, all // in the background // - restoreFromBackup is not set: we initHealthCheck right away if *restoreFromBackup { go func() { // restoreFromBackup wil just be a regular action // (same as if it was triggered remotely) if err := agent.RestoreData(batchCtx, logutil.NewConsoleLogger(), false /* deleteBeforeRestore */); err != nil { println(fmt.Sprintf("RestoreFromBackup failed: %v", err)) log.Fatalf("RestoreFromBackup failed: %v", err) } // after the restore is done, start health check agent.initHealthCheck() }() } else { // update our state if err := agent.refreshTablet(batchCtx, "Start"); err != nil { return nil, err } // synchronously start health check if needed agent.initHealthCheck() } // Start periodic Orchestrator self-registration, if configured. if agent.orc != nil { go agent.orc.DiscoverLoop(agent) } return agent, nil }
// TestInitTablet will test the InitTablet code creates / updates the // tablet node correctly. Note we modify global parameters (the flags) // so this has to be in one test. func TestInitTablet(t *testing.T) { ctx := context.Background() db := fakesqldb.Register() ts := zktestserver.New(t, []string{"cell1", "cell2"}) tabletAlias := &topodatapb.TabletAlias{ Cell: "cell1", Uid: 1, } // start with a tablet record that doesn't exist port := int32(1234) gRPCPort := int32(3456) mysqlDaemon := mysqlctl.NewFakeMysqlDaemon(db) agent := &ActionAgent{ TopoServer: ts, TabletAlias: tabletAlias, MysqlDaemon: mysqlDaemon, DBConfigs: dbconfigs.DBConfigs{}, SchemaOverrides: nil, BinlogPlayerMap: nil, batchCtx: ctx, History: history.New(historyLength), lastHealthMapCount: new(stats.Int), _healthy: fmt.Errorf("healthcheck not run yet"), } // let's use a real tablet in a shard, that will create // the keyspace and shard. *tabletHostname = "localhost" *initTabletType = "replica" *initKeyspace = "test_keyspace" *initShard = "-80" tabletAlias = &topodatapb.TabletAlias{ Cell: "cell1", Uid: 2, } agent.TabletAlias = tabletAlias if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type) failed: %v", err) } si, err := ts.GetShard(ctx, "test_keyspace", "-80") if err != nil { t.Fatalf("GetShard failed: %v", err) } if len(si.Cells) != 1 || si.Cells[0] != "cell1" { t.Errorf("shard.Cells not updated properly: %v", si) } ti, err := ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != topodatapb.TabletType_REPLICA { t.Errorf("wrong tablet type: %v", ti.Type) } if ti.Hostname != "localhost" { t.Errorf("wrong hostname for tablet: %v", ti.Hostname) } if ti.PortMap["vt"] != port { t.Errorf("wrong port for tablet: %v", ti.PortMap["vt"]) } if ti.PortMap["grpc"] != gRPCPort { t.Errorf("wrong gRPC port for tablet: %v", ti.PortMap["grpc"]) } // try to init again, this time with health check on *initTabletType = "" *targetTabletType = "replica" if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type, healthcheck) failed: %v", err) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != topodatapb.TabletType_SPARE { t.Errorf("wrong tablet type: %v", ti.Type) } // update shard's master to our alias, then try to init again si, err = ts.GetShard(ctx, "test_keyspace", "-80") if err != nil { t.Fatalf("GetShard failed: %v", err) } si.MasterAlias = tabletAlias if err := ts.UpdateShard(ctx, si); err != nil { t.Fatalf("UpdateShard failed: %v", err) } if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type, healthcheck) failed: %v", err) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } // It should still be spare, because the tablet record doesn't agree. if ti.Type != topodatapb.TabletType_SPARE { t.Errorf("wrong tablet type: %v", ti.Type) } // Fix the tablet record to agree that we're master. ti.Type = topodatapb.TabletType_MASTER if err := ts.UpdateTablet(ctx, ti); err != nil { t.Fatalf("UpdateTablet failed: %v", err) } if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type, healthcheck) failed: %v", err) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != topodatapb.TabletType_MASTER { t.Errorf("wrong tablet type: %v", ti.Type) } // init again with the tablet_type set, no healthcheck // (also check db name override and tags here) *initTabletType = "replica" *targetTabletType = "" *initDbNameOverride = "DBNAME" initTags.Set("aaa:bbb") if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type, healthcheck) failed: %v", err) } ti, err = ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) } if ti.Type != topodatapb.TabletType_MASTER { t.Errorf("wrong tablet type: %v", ti.Type) } if ti.DbNameOverride != "DBNAME" { t.Errorf("wrong tablet DbNameOverride: %v", ti.DbNameOverride) } if len(ti.Tags) != 1 || ti.Tags["aaa"] != "bbb" { t.Errorf("wrong tablet tags: %v", ti.Tags) } }