Skip to content

Commit

Permalink
Merge pull request #10905 from planetscale/vtctld-full-status
Browse files Browse the repository at this point in the history
Add GetFullStatus RPC to vtctld
  • Loading branch information
deepthi authored Aug 4, 2022
2 parents e2851b6 + 381a066 commit 93bdc0e
Show file tree
Hide file tree
Showing 18 changed files with 2,657 additions and 1,444 deletions.
33 changes: 33 additions & 0 deletions go/cmd/vtctldclient/command/tablets.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ Note: hook names may not contain slash (/) characters.
Args: cobra.MinimumNArgs(2),
RunE: commandExecuteHook,
}
// GetFullStatus makes a FullStatus gRPC call to a vttablet.
GetFullStatus = &cobra.Command{
Use: "GetFullStatus <alias>",
Short: "Outputs a JSON structure that contains full status of MySQL including the replication information, semi-sync information, GTID information among others.",
DisableFlagsInUseLine: true,
Args: cobra.ExactArgs(1),
RunE: commandGetFullStatus,
}
// GetPermissions makes a GetPermissions gRPC call to a vtctld.
GetPermissions = &cobra.Command{
Use: "GetPermissions <tablet_alias>",
Expand Down Expand Up @@ -299,6 +307,30 @@ func commandExecuteHook(cmd *cobra.Command, args []string) error {
return nil
}

func commandGetFullStatus(cmd *cobra.Command, args []string) error {
aliasStr := cmd.Flags().Arg(0)
alias, err := topoproto.ParseTabletAlias(aliasStr)
if err != nil {
return err
}

cli.FinishedParsing(cmd)

resp, err := client.GetFullStatus(commandCtx, &vtctldatapb.GetFullStatusRequest{TabletAlias: alias})
if err != nil {
return err
}

data, err := cli.MarshalJSON(resp.Status)
if err != nil {
return err
}

fmt.Printf("%s\n", data)

return nil
}

func commandGetPermissions(cmd *cobra.Command, args []string) error {
alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
if err != nil {
Expand Down Expand Up @@ -596,6 +628,7 @@ func init() {
Root.AddCommand(DeleteTablets)

Root.AddCommand(ExecuteHook)
Root.AddCommand(GetFullStatus)
Root.AddCommand(GetPermissions)
Root.AddCommand(GetTablet)

Expand Down
5 changes: 3 additions & 2 deletions go/test/endtoend/cluster/cluster_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ type LocalProcessCluster struct {
VtctlMajorVersion int

// standalone executable
VtctlclientProcess VtctlClientProcess
VtctlProcess VtctlProcess
VtctlclientProcess VtctlClientProcess
VtctldClientProcess VtctldClientProcess
VtctlProcess VtctlProcess

// background executable processes
TopoProcess TopoProcess
Expand Down
103 changes: 103 additions & 0 deletions go/test/endtoend/reparent/newfeaturetest/reparent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ limitations under the License.
package newfeaturetest

import (
"strconv"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"google.golang.org/protobuf/encoding/protojson"

"vitess.io/vitess/go/mysql"
"vitess.io/vitess/go/test/endtoend/cluster"
"vitess.io/vitess/go/test/endtoend/reparent/utils"
replicationdatapb "vitess.io/vitess/go/vt/proto/replicationdata"
)

// TestCrossCellDurability tests 2 things -
Expand Down Expand Up @@ -66,3 +72,100 @@ func TestCrossCellDurability(t *testing.T) {
utils.CheckSemiSyncSetupCorrectly(t, newReplica, "ON")
}
}

// TestFullStatus tests that the RPC FullStatus works as intended.
func TestFullStatus(t *testing.T) {
defer cluster.PanicHandler(t)
clusterInstance := utils.SetupReparentCluster(t, "semi_sync")
defer utils.TeardownCluster(clusterInstance)
tablets := clusterInstance.Keyspaces[0].Shards[0].Vttablets
utils.ConfirmReplication(t, tablets[0], []*cluster.Vttablet{tablets[1], tablets[2], tablets[3]})

// Check that full status gives the correct result for a primary tablet
primaryStatusString, err := clusterInstance.VtctldClientProcess.ExecuteCommandWithOutput("GetFullStatus", tablets[0].Alias)
require.NoError(t, err)
primaryStatus := &replicationdatapb.FullStatus{}
err = protojson.Unmarshal([]byte(primaryStatusString), primaryStatus)
require.NoError(t, err)
assert.NotEmpty(t, primaryStatus.ServerUuid)
assert.NotEmpty(t, primaryStatus.ServerId)
// For a primary tablet there is no replication status
assert.Nil(t, primaryStatus.ReplicationStatus)
assert.Contains(t, primaryStatus.PrimaryStatus.String(), "vt-0000000101-bin")
assert.Equal(t, primaryStatus.GtidPurged, "MySQL56/")
assert.False(t, primaryStatus.ReadOnly)
assert.True(t, primaryStatus.SemiSyncPrimaryEnabled)
assert.True(t, primaryStatus.SemiSyncReplicaEnabled)
assert.True(t, primaryStatus.SemiSyncPrimaryStatus)
assert.False(t, primaryStatus.SemiSyncReplicaStatus)
assert.EqualValues(t, 3, primaryStatus.SemiSyncPrimaryClients)
assert.EqualValues(t, 1000000000000000000, primaryStatus.SemiSyncPrimaryTimeout)
assert.EqualValues(t, 1, primaryStatus.SemiSyncWaitForReplicaCount)
assert.Equal(t, "ROW", primaryStatus.BinlogFormat)
assert.Equal(t, "FULL", primaryStatus.BinlogRowImage)
assert.Equal(t, "ON", primaryStatus.GtidMode)
assert.True(t, primaryStatus.LogReplicaUpdates)
assert.True(t, primaryStatus.LogBinEnabled)
assert.Regexp(t, `[58]\.[07].*`, primaryStatus.Version)
assert.NotEmpty(t, primaryStatus.VersionComment)

// Check that full status gives the correct result for a replica tablet
replicaStatusString, err := clusterInstance.VtctldClientProcess.ExecuteCommandWithOutput("GetFullStatus", tablets[1].Alias)
require.NoError(t, err)
replicaStatus := &replicationdatapb.FullStatus{}
err = protojson.Unmarshal([]byte(replicaStatusString), replicaStatus)
require.NoError(t, err)
assert.NotEmpty(t, replicaStatus.ServerUuid)
assert.NotEmpty(t, replicaStatus.ServerId)
assert.Contains(t, replicaStatus.ReplicationStatus.Position, "MySQL56/"+replicaStatus.ReplicationStatus.SourceUuid)
assert.EqualValues(t, mysql.ReplicationStateRunning, replicaStatus.ReplicationStatus.IoState)
assert.EqualValues(t, mysql.ReplicationStateRunning, replicaStatus.ReplicationStatus.SqlState)
assert.Equal(t, fileNameFromPosition(replicaStatus.ReplicationStatus.FilePosition), fileNameFromPosition(primaryStatus.PrimaryStatus.FilePosition))
assert.LessOrEqual(t, rowNumberFromPosition(replicaStatus.ReplicationStatus.FilePosition), rowNumberFromPosition(primaryStatus.PrimaryStatus.FilePosition))
assert.Equal(t, replicaStatus.ReplicationStatus.RelayLogSourceBinlogEquivalentPosition, primaryStatus.PrimaryStatus.FilePosition)
assert.Contains(t, replicaStatus.ReplicationStatus.RelayLogFilePosition, "vt-0000000102-relay")
assert.Equal(t, replicaStatus.ReplicationStatus.Position, primaryStatus.PrimaryStatus.Position)
assert.Equal(t, replicaStatus.ReplicationStatus.RelayLogPosition, primaryStatus.PrimaryStatus.Position)
assert.Empty(t, replicaStatus.ReplicationStatus.LastIoError)
assert.Empty(t, replicaStatus.ReplicationStatus.LastSqlError)
assert.Equal(t, replicaStatus.ReplicationStatus.SourceUuid, primaryStatus.ServerUuid)
assert.LessOrEqual(t, int(replicaStatus.ReplicationStatus.ReplicationLagSeconds), 1)
assert.False(t, replicaStatus.ReplicationStatus.ReplicationLagUnknown)
assert.EqualValues(t, 0, replicaStatus.ReplicationStatus.SqlDelay)
assert.False(t, replicaStatus.ReplicationStatus.SslAllowed)
assert.False(t, replicaStatus.ReplicationStatus.HasReplicationFilters)
assert.False(t, replicaStatus.ReplicationStatus.UsingGtid)
assert.True(t, replicaStatus.ReplicationStatus.AutoPosition)
assert.Equal(t, replicaStatus.ReplicationStatus.SourceHost, utils.Hostname)
assert.EqualValues(t, replicaStatus.ReplicationStatus.SourcePort, tablets[0].MySQLPort)
assert.Equal(t, replicaStatus.ReplicationStatus.SourceUser, "vt_repl")
assert.Contains(t, replicaStatus.PrimaryStatus.String(), "vt-0000000102-bin")
assert.Equal(t, replicaStatus.GtidPurged, "MySQL56/")
assert.True(t, replicaStatus.ReadOnly)
assert.False(t, replicaStatus.SemiSyncPrimaryEnabled)
assert.True(t, replicaStatus.SemiSyncReplicaEnabled)
assert.False(t, replicaStatus.SemiSyncPrimaryStatus)
assert.True(t, replicaStatus.SemiSyncReplicaStatus)
assert.EqualValues(t, 0, replicaStatus.SemiSyncPrimaryClients)
assert.EqualValues(t, 1000000000000000000, replicaStatus.SemiSyncPrimaryTimeout)
assert.EqualValues(t, 1, replicaStatus.SemiSyncWaitForReplicaCount)
assert.Equal(t, "ROW", replicaStatus.BinlogFormat)
assert.Equal(t, "FULL", replicaStatus.BinlogRowImage)
assert.Equal(t, "ON", replicaStatus.GtidMode)
assert.True(t, replicaStatus.LogReplicaUpdates)
assert.True(t, replicaStatus.LogBinEnabled)
assert.Regexp(t, `[58]\.[07].*`, replicaStatus.Version)
assert.NotEmpty(t, replicaStatus.VersionComment)
}

// fileNameFromPosition gets the file name from the position
func fileNameFromPosition(pos string) string {
return pos[0 : len(pos)-4]
}

// rowNumberFromPosition gets the row number from the position
func rowNumberFromPosition(pos string) int {
rowNumStr := pos[len(pos)-4:]
rowNum, _ := strconv.Atoi(rowNumStr)
return rowNum
}
93 changes: 0 additions & 93 deletions go/test/endtoend/reparent/plannedreparent/reparent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@ package plannedreparent
import (
"context"
"fmt"
"strconv"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"vitess.io/vitess/go/mysql"
"vitess.io/vitess/go/test/endtoend/cluster"
"vitess.io/vitess/go/test/endtoend/reparent/utils"
"vitess.io/vitess/go/vt/log"
Expand Down Expand Up @@ -439,94 +437,3 @@ func TestReplicationStatus(t *testing.T) {
assert.NotEmpty(t, replicationStatus.Position)
assert.NotEmpty(t, replicationStatus.RelayLogPosition)
}

// TestFullStatus tests that the RPC FullStatus works as intended.
func TestFullStatus(t *testing.T) {
defer cluster.PanicHandler(t)
clusterInstance := utils.SetupReparentCluster(t, "semi_sync")
defer utils.TeardownCluster(clusterInstance)
tablets := clusterInstance.Keyspaces[0].Shards[0].Vttablets
utils.ConfirmReplication(t, tablets[0], []*cluster.Vttablet{tablets[1], tablets[2], tablets[3]})

// Check that full status gives the correct result for a primary tablet
primaryStatus, err := utils.TmcFullStatus(context.Background(), tablets[0])
require.NoError(t, err)
assert.NotEmpty(t, primaryStatus.ServerUuid)
assert.NotEmpty(t, primaryStatus.ServerId)
// For a primary tablet there is no replication status
assert.Nil(t, primaryStatus.ReplicationStatus)
assert.Contains(t, primaryStatus.PrimaryStatus.String(), "vt-0000000101-bin")
assert.Equal(t, primaryStatus.GtidPurged, "MySQL56/")
assert.False(t, primaryStatus.ReadOnly)
assert.True(t, primaryStatus.SemiSyncPrimaryEnabled)
assert.True(t, primaryStatus.SemiSyncReplicaEnabled)
assert.True(t, primaryStatus.SemiSyncPrimaryStatus)
assert.False(t, primaryStatus.SemiSyncReplicaStatus)
assert.EqualValues(t, 3, primaryStatus.SemiSyncPrimaryClients)
assert.EqualValues(t, 1000000000000000000, primaryStatus.SemiSyncPrimaryTimeout)
assert.EqualValues(t, 1, primaryStatus.SemiSyncWaitForReplicaCount)
assert.Equal(t, "ROW", primaryStatus.BinlogFormat)
assert.Equal(t, "FULL", primaryStatus.BinlogRowImage)
assert.Equal(t, "ON", primaryStatus.GtidMode)
assert.True(t, primaryStatus.LogReplicaUpdates)
assert.True(t, primaryStatus.LogBinEnabled)
assert.Regexp(t, `[58]\.[07].*`, primaryStatus.Version)
assert.NotEmpty(t, primaryStatus.VersionComment)

// Check that full status gives the correct result for a replica tablet
replicaStatus, err := utils.TmcFullStatus(context.Background(), tablets[1])
require.NoError(t, err)
assert.NotEmpty(t, replicaStatus.ServerUuid)
assert.NotEmpty(t, replicaStatus.ServerId)
assert.Contains(t, replicaStatus.ReplicationStatus.Position, "MySQL56/"+replicaStatus.ReplicationStatus.SourceUuid)
assert.EqualValues(t, mysql.ReplicationStateRunning, replicaStatus.ReplicationStatus.IoState)
assert.EqualValues(t, mysql.ReplicationStateRunning, replicaStatus.ReplicationStatus.SqlState)
assert.Equal(t, fileNameFromPosition(replicaStatus.ReplicationStatus.FilePosition), fileNameFromPosition(primaryStatus.PrimaryStatus.FilePosition))
assert.LessOrEqual(t, rowNumberFromPosition(replicaStatus.ReplicationStatus.FilePosition), rowNumberFromPosition(primaryStatus.PrimaryStatus.FilePosition))
assert.Equal(t, replicaStatus.ReplicationStatus.RelayLogSourceBinlogEquivalentPosition, primaryStatus.PrimaryStatus.FilePosition)
assert.Contains(t, replicaStatus.ReplicationStatus.RelayLogFilePosition, "vt-0000000102-relay")
assert.Equal(t, replicaStatus.ReplicationStatus.Position, primaryStatus.PrimaryStatus.Position)
assert.Equal(t, replicaStatus.ReplicationStatus.RelayLogPosition, primaryStatus.PrimaryStatus.Position)
assert.Empty(t, replicaStatus.ReplicationStatus.LastIoError)
assert.Empty(t, replicaStatus.ReplicationStatus.LastSqlError)
assert.Equal(t, replicaStatus.ReplicationStatus.SourceUuid, primaryStatus.ServerUuid)
assert.LessOrEqual(t, int(replicaStatus.ReplicationStatus.ReplicationLagSeconds), 1)
assert.False(t, replicaStatus.ReplicationStatus.ReplicationLagUnknown)
assert.EqualValues(t, 0, replicaStatus.ReplicationStatus.SqlDelay)
assert.False(t, replicaStatus.ReplicationStatus.SslAllowed)
assert.False(t, replicaStatus.ReplicationStatus.HasReplicationFilters)
assert.False(t, replicaStatus.ReplicationStatus.UsingGtid)
assert.True(t, replicaStatus.ReplicationStatus.AutoPosition)
assert.Equal(t, replicaStatus.ReplicationStatus.SourceHost, utils.Hostname)
assert.EqualValues(t, replicaStatus.ReplicationStatus.SourcePort, tablets[0].MySQLPort)
assert.Equal(t, replicaStatus.ReplicationStatus.SourceUser, "vt_repl")
assert.Contains(t, replicaStatus.PrimaryStatus.String(), "vt-0000000102-bin")
assert.Equal(t, replicaStatus.GtidPurged, "MySQL56/")
assert.True(t, replicaStatus.ReadOnly)
assert.False(t, replicaStatus.SemiSyncPrimaryEnabled)
assert.True(t, replicaStatus.SemiSyncReplicaEnabled)
assert.False(t, replicaStatus.SemiSyncPrimaryStatus)
assert.True(t, replicaStatus.SemiSyncReplicaStatus)
assert.EqualValues(t, 0, replicaStatus.SemiSyncPrimaryClients)
assert.EqualValues(t, 1000000000000000000, replicaStatus.SemiSyncPrimaryTimeout)
assert.EqualValues(t, 1, replicaStatus.SemiSyncWaitForReplicaCount)
assert.Equal(t, "ROW", replicaStatus.BinlogFormat)
assert.Equal(t, "FULL", replicaStatus.BinlogRowImage)
assert.Equal(t, "ON", replicaStatus.GtidMode)
assert.True(t, replicaStatus.LogReplicaUpdates)
assert.True(t, replicaStatus.LogBinEnabled)
assert.Regexp(t, `[58]\.[07].*`, replicaStatus.Version)
assert.NotEmpty(t, replicaStatus.VersionComment)
}

// fileNameFromPosition gets the file name from the position
func fileNameFromPosition(pos string) string {
return pos[0 : len(pos)-4]
}

// rowNumberFromPosition gets the row number from the position
func rowNumberFromPosition(pos string) int {
rowNumStr := pos[len(pos)-4:]
rowNum, _ := strconv.Atoi(rowNumStr)
return rowNum
}
21 changes: 2 additions & 19 deletions go/test/endtoend/reparent/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ import (
"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/test/endtoend/cluster"
"vitess.io/vitess/go/vt/log"
tmc "vitess.io/vitess/go/vt/vttablet/grpctmclient"

replicationdatapb "vitess.io/vitess/go/vt/proto/replicationdata"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
)
Expand Down Expand Up @@ -157,8 +155,8 @@ func setupCluster(ctx context.Context, t *testing.T, shardName string, cells []s
}
}
if clusterInstance.VtctlMajorVersion >= 14 {
vtctldClientProcess := cluster.VtctldClientProcessInstance("localhost", clusterInstance.VtctldProcess.GrpcPort, clusterInstance.TmpDirectory)
out, err := vtctldClientProcess.ExecuteCommandWithOutput("SetKeyspaceDurabilityPolicy", KeyspaceName, fmt.Sprintf("--durability-policy=%s", durability))
clusterInstance.VtctldClientProcess = *cluster.VtctldClientProcessInstance("localhost", clusterInstance.VtctldProcess.GrpcPort, clusterInstance.TmpDirectory)
out, err := clusterInstance.VtctldClientProcess.ExecuteCommandWithOutput("SetKeyspaceDurabilityPolicy", KeyspaceName, fmt.Sprintf("--durability-policy=%s", durability))
require.NoError(t, err, out)
}

Expand Down Expand Up @@ -736,18 +734,3 @@ func ReplicationThreadsStatus(t *testing.T, status *replicationdatapb.Status, vt
}
return ioThread, sqlThread
}

// TmcFullStatus retuns the result of the TabletManagerClient RPC FullStatus
func TmcFullStatus(ctx context.Context, tablet *cluster.Vttablet) (*replicationdatapb.FullStatus, error) {
// create tablet manager client
tmClient := tmc.NewClient()

vttablet := getTablet(tablet.GrpcPort)
return tmClient.FullStatus(ctx, vttablet)
}

func getTablet(tabletGrpcPort int) *topodatapb.Tablet {
portMap := make(map[string]int32)
portMap["grpc"] = int32(tabletGrpcPort)
return &topodatapb.Tablet{Hostname: Hostname, PortMap: portMap}
}
Loading

0 comments on commit 93bdc0e

Please sign in to comment.