Skip to content

Commit

Permalink
SwitchTraffic should switch everything when no tablet_types provided (v…
Browse files Browse the repository at this point in the history
…itessio#10434)

* We should switch everything when no tablet_types provided

* Update help output to clarify behavior

* Update SwitchTraffic [all|default] tests for user facing client behavior

Meaning that we don't explicitly specify a tablet_types value and
leverage the command default which should be:
in_order:RDONLY,REPLICA,PRIMARY

This also requires that the tests actually create RDONLY tablets, so
do that for the basic v2 workflow tests.

* Properly handle SwitchTraffic default

And test traffic switching of RDONLY tablets

* Only add RDONLY tables in default Cell

Signed-off-by: Matt Lord <mattalord@gmail.com>
Signed-off-by: Vilius Okockis <vilius.okockis@vinted.com>
  • Loading branch information
mattlord authored and DeathBorn committed Apr 12, 2024
1 parent d315061 commit 9259da7
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 22 deletions.
19 changes: 11 additions & 8 deletions go/test/endtoend/vreplication/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,14 +317,17 @@ func (vc *VitessCluster) AddShards(t testing.TB, cells []*Cell, keyspace *Keyspa
tablets = append(tablets, tablet)
dbProcesses = append(dbProcesses, proc)
}
for i := 0; i < numRdonly; i++ {
log.Infof("Adding RdOnly tablet")
tablet, proc, err := vc.AddTablet(t, cell, keyspace, shard, "rdonly", tabletID+tabletIndex)
require.NoError(t, err)
require.NotNil(t, tablet)
tabletIndex++
tablets = append(tablets, tablet)
dbProcesses = append(dbProcesses, proc)
// Only create RDONLY tablets in the default cell
if cell.Name == cluster.DefaultCell {
for i := 0; i < numRdonly; i++ {
log.Infof("Adding RdOnly tablet")
tablet, proc, err := vc.AddTablet(t, cell, keyspace, shard, "rdonly", tabletID+tabletIndex)
require.NoError(t, err)
require.NotNil(t, tablet)
tabletIndex++
tablets = append(tablets, tablet)
dbProcesses = append(dbProcesses, proc)
}
}

for ind, proc := range dbProcesses {
Expand Down
34 changes: 28 additions & 6 deletions go/test/endtoend/vreplication/resharding_workflows_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ const (
)

var (
targetTab1, targetTab2, targetReplicaTab1 *cluster.VttabletProcess
sourceReplicaTab, sourceTab *cluster.VttabletProcess
targetTab1, targetTab2, targetReplicaTab1, targetRdonlyTab1 *cluster.VttabletProcess
sourceTab, sourceReplicaTab, sourceRdonlyTab *cluster.VttabletProcess

lastOutput string
currentWorkflowType wrangler.VReplicationWorkflowType
Expand Down Expand Up @@ -142,12 +142,16 @@ func tstWorkflowReverseWrites(t *testing.T) {
require.NoError(t, tstWorkflowAction(t, workflowActionReverseTraffic, "master", ""))
}

// tstWorkflowSwitchReadsAndWrites tests that SwitchWrites w/o any user provided --tablet_types
// value switches all traffic
func tstWorkflowSwitchReadsAndWrites(t *testing.T) {
require.NoError(t, tstWorkflowAction(t, workflowActionSwitchTraffic, "replica,rdonly,master", ""))
require.NoError(t, tstWorkflowAction(t, workflowActionSwitchTraffic, "", ""))
}

// tstWorkflowReversesReadsAndWrites tests that SwitchWrites w/o any user provided --tablet_types
// value switches all traffic in reverse
func tstWorkflowReverseReadsAndWrites(t *testing.T) {
require.NoError(t, tstWorkflowAction(t, workflowActionReverseTraffic, "replica,rdonly,master", ""))
require.NoError(t, tstWorkflowAction(t, workflowActionReverseTraffic, "", ""))
}

func tstWorkflowComplete(t *testing.T) error {
Expand Down Expand Up @@ -231,6 +235,8 @@ func getCurrentState(t *testing.T) string {
// but CI currently fails on creating multiple clusters even after the previous ones are torn down

func TestBasicV2Workflows(t *testing.T) {
defaultRdonly = 1
defer func() { defaultRdonly = 0 }()
vc = setupCluster(t)
defer vtgateConn.Close()
defer vc.TearDown(t)
Expand Down Expand Up @@ -365,8 +371,10 @@ func testRestOfWorkflow(t *testing.T) {

tstWorkflowSwitchReadsAndWrites(t)
validateReadsRouteToTarget(t, "replica")
validateReadsRoute(t, "rdonly", targetRdonlyTab1)
validateWritesRouteToTarget(t)
tstWorkflowReverseReadsAndWrites(t)
validateReadsRoute(t, "rdonly", sourceRdonlyTab)
validateReadsRouteToSource(t, "replica")
validateWritesRouteToSource(t)

Expand All @@ -377,6 +385,7 @@ func testRestOfWorkflow(t *testing.T) {

// fully switch and complete
tstWorkflowSwitchReadsAndWrites(t)
validateReadsRoute(t, "rdonly", targetRdonlyTab1)
validateReadsRouteToTarget(t, "replica")
validateWritesRouteToTarget(t)

Expand All @@ -402,13 +411,15 @@ func setupCluster(t *testing.T) *VitessCluster {
require.NotNil(t, vtgate)
vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", "product", "0"), 1)
vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", "product", "0"), 2)
vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", "product", "0"), 1)

vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort)
verifyClusterHealth(t, vc)
insertInitialData(t)

sourceReplicaTab = vc.Cells[defaultCell.Name].Keyspaces["product"].Shards["0"].Tablets["zone1-101"].Vttablet
sourceTab = vc.Cells[defaultCell.Name].Keyspaces["product"].Shards["0"].Tablets["zone1-100"].Vttablet
sourceReplicaTab = vc.Cells[defaultCell.Name].Keyspaces["product"].Shards["0"].Tablets["zone1-101"].Vttablet
sourceRdonlyTab = vc.Cells[defaultCell.Name].Keyspaces["product"].Shards["0"].Tablets["zone1-102"].Vttablet

return vc
}
Expand All @@ -430,10 +441,17 @@ func setupCustomerKeyspace(t *testing.T) {
if err := vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", "customer", "80-"), 2); err != nil {
t.Fatal(err)
}
if err := vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", "customer", "-80"), 1); err != nil {
t.Fatal(err)
}
if err := vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", "customer", "80-"), 1); err != nil {
t.Fatal(err)
}
custKs := vc.Cells[defaultCell.Name].Keyspaces["customer"]
targetTab1 = custKs.Shards["-80"].Tablets["zone1-200"].Vttablet
targetTab2 = custKs.Shards["80-"].Tablets["zone1-300"].Vttablet
targetReplicaTab1 = custKs.Shards["-80"].Tablets["zone1-201"].Vttablet
targetRdonlyTab1 = custKs.Shards["-80"].Tablets["zone1-202"].Vttablet
}

func TestSwitchReadsWritesInAnyOrder(t *testing.T) {
Expand Down Expand Up @@ -556,12 +574,16 @@ func createAdditionalCustomerShards(t *testing.T, shards string) {
if err := vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", ksName, shardName), 2); err != nil {
t.Fatal(err)
}
if err := vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", ksName, shardName), 1); err != nil {
require.NoError(t, err)
}
}
custKs := vc.Cells[defaultCell.Name].Keyspaces[ksName]
targetTab2 = custKs.Shards["80-c0"].Tablets["zone1-600"].Vttablet
targetTab1 = custKs.Shards["40-80"].Tablets["zone1-500"].Vttablet
targetReplicaTab1 = custKs.Shards["-40"].Tablets["zone1-401"].Vttablet

sourceReplicaTab = custKs.Shards["-80"].Tablets["zone1-201"].Vttablet
sourceTab = custKs.Shards["-80"].Tablets["zone1-200"].Vttablet
sourceReplicaTab = custKs.Shards["-80"].Tablets["zone1-201"].Vttablet
sourceRdonlyTab = custKs.Shards["-80"].Tablets["zone1-202"].Vttablet
}
31 changes: 23 additions & 8 deletions go/vt/vtctl/vtctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -2027,11 +2027,11 @@ func commandVRWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *fla
workflowType wrangler.VReplicationWorkflowType) error {

cells := subFlags.String("cells", "", "Cell(s) or CellAlias(es) (comma-separated) to replicate from.")
tabletTypes := subFlags.String("tablet_types", "in_order:REPLICA,MASTER", "Source tablet types to replicate from (e.g. MASTER, REPLICA, RDONLY). Defaults to --vreplication_tablet_type parameter value for the tablet, which has the default value of in_order:REPLICA,MASTER.")
dryRun := subFlags.Bool("dry_run", false, "Does a dry run of SwitchReads and only reports the actions to be taken. -dry_run is only supported for SwitchTraffic, ReverseTraffic and Complete.")
timeout := subFlags.Duration("timeout", 30*time.Second, "Specifies the maximum time to wait, in seconds, for vreplication to catch up on master migrations. The migration will be cancelled on a timeout.")
reverseReplication := subFlags.Bool("reverse_replication", true, "Also reverse the replication")
keepData := subFlags.Bool("keep_data", false, "Do not drop tables or shards (if true, only vreplication artifacts are cleaned up)")
tabletTypes := subFlags.String("tablet_types", "in_order:REPLICA,MASTER", "Source tablet types to replicate from (e.g. MASTER, REPLICA, RDONLY). Defaults to --vreplication_tablet_type parameter value for the tablet, which has the default value of in_order:REPLICA,MASTER. Note: SwitchTraffic overrides this default and uses in_order:RDONLY,REPLICA,MASTER to switch all traffic by default.")
dryRun := subFlags.Bool("dry_run", false, "Does a dry run of SwitchReads and only reports the actions to be taken. --dry_run is only supported for SwitchTraffic, ReverseTraffic and Complete.")
timeout := subFlags.Duration("timeout", 30*time.Second, "Specifies the maximum time to wait, in seconds, for vreplication to catch up on master migrations. The migration will be cancelled on a timeout. --timeout is only supported for SwitchTraffic and ReverseTraffic.")
reverseReplication := subFlags.Bool("reverse_replication", true, "Also reverse the replication (default true). --reverse_replication is only supported for SwitchTraffic.")
keepData := subFlags.Bool("keep_data", false, "Do not drop tables or shards (if true, only vreplication artifacts are cleaned up). --keep_data is only supported for Complete and Cancel.")

autoStart := subFlags.Bool("auto_start", true, "If false, streams will start in the Stopped state and will need to be explicitly started")
stopAfterCopy := subFlags.Bool("stop_after_copy", false, "Streams will be stopped once the copy phase is completed")
Expand Down Expand Up @@ -2179,9 +2179,12 @@ func commandVRWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *fla
vrwp.TabletTypes = *tabletTypes
case vReplicationWorkflowActionSwitchTraffic, vReplicationWorkflowActionReverseTraffic:
vrwp.Cells = *cells
vrwp.TabletTypes = *tabletTypes
if vrwp.TabletTypes == "" {
vrwp.TabletTypes = "in_order:REPLICA,MASTER"
if userPassedFlag(subFlags, "tablet_types") {
vrwp.TabletTypes = *tabletTypes
} else {
// When no tablet types are specified we are supposed to switch all traffic so
// we override the normal default for tablet_types.
vrwp.TabletTypes = "in_order:RDONLY,REPLICA,MASTER"
}
vrwp.Timeout = *timeout
vrwp.EnableReverseReplication = *reverseReplication
Expand Down Expand Up @@ -3806,3 +3809,15 @@ func PrintAllCommands(logger logutil.Logger) {
logger.Printf("\n")
}
}

// userPassedFlag returns true if the flag name given was provided
// as a command-line argument by the user.
func userPassedFlag(flags *flag.FlagSet, name string) bool {
passed := false
flags.Visit(func(f *flag.Flag) {
if f.Name == name {
passed = true
}
})
return passed
}

0 comments on commit 9259da7

Please sign in to comment.