vitess.io/vitess@v0.16.2/go/cmd/vtctldclient/command/tablets.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package command
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/spf13/cobra"
    26  
    27  	"vitess.io/vitess/go/cmd/vtctldclient/cli"
    28  	"vitess.io/vitess/go/protoutil"
    29  	"vitess.io/vitess/go/vt/topo/topoproto"
    30  
    31  	tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
    32  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    33  	vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata"
    34  )
    35  
    36  var (
    37  	// ChangeTabletType makes a ChangeTabletType gRPC call to a vtctld.
    38  	ChangeTabletType = &cobra.Command{
    39  		Use:   "ChangeTabletType [--dry-run] <alias> <tablet-type>",
    40  		Short: "Changes the db type for the specified tablet, if possible.",
    41  		Long: `Changes the db type for the specified tablet, if possible.
    42  
    43  This command is used primarily to arrange replicas, and it will not convert a primary.
    44  NOTE: This command automatically updates the serving graph.`,
    45  		DisableFlagsInUseLine: true,
    46  		Args:                  cobra.ExactArgs(2),
    47  		RunE:                  commandChangeTabletType,
    48  	}
    49  	// DeleteTablets makes a DeleteTablets gRPC call to a vtctld.
    50  	DeleteTablets = &cobra.Command{
    51  		Use:                   "DeleteTablets <alias> [ <alias> ... ]",
    52  		Short:                 "Deletes tablet(s) from the topology.",
    53  		DisableFlagsInUseLine: true,
    54  		Args:                  cobra.MinimumNArgs(1),
    55  		RunE:                  commandDeleteTablets,
    56  	}
    57  	// ExecuteHook makes an ExecuteHook gRPC call to a vtctld.
    58  	ExecuteHook = &cobra.Command{
    59  		Use:   "ExecuteHook <alias> <hook_name> [<param1=value1> ...]",
    60  		Short: "Runs the specified hook on the given tablet.",
    61  		Long: `Runs the specified hook on the given tablet.
    62  
    63  A hook is an executable script that resides in the ${VTROOT}/vthook directory.
    64  For ExecuteHook, this is on the tablet requested, not on the vtctld or the host
    65  running the vtctldclient.
    66  
    67  Any key-value pairs passed after the hook name will be passed as parameters to
    68  the hook on the tablet.
    69  
    70  Note: hook names may not contain slash (/) characters.
    71  `,
    72  		DisableFlagsInUseLine: true,
    73  		Args:                  cobra.MinimumNArgs(2),
    74  		RunE:                  commandExecuteHook,
    75  	}
    76  	// GetFullStatus makes a FullStatus gRPC call to a vttablet.
    77  	GetFullStatus = &cobra.Command{
    78  		Use:                   "GetFullStatus <alias>",
    79  		Short:                 "Outputs a JSON structure that contains full status of MySQL including the replication information, semi-sync information, GTID information among others.",
    80  		DisableFlagsInUseLine: true,
    81  		Args:                  cobra.ExactArgs(1),
    82  		RunE:                  commandGetFullStatus,
    83  	}
    84  	// GetPermissions makes a GetPermissions gRPC call to a vtctld.
    85  	GetPermissions = &cobra.Command{
    86  		Use:                   "GetPermissions <tablet_alias>",
    87  		Short:                 "Displays the permissions for a tablet.",
    88  		DisableFlagsInUseLine: true,
    89  		Args:                  cobra.ExactArgs(1),
    90  		RunE:                  commandGetPermissions,
    91  	}
    92  	// GetTablet makes a GetTablet gRPC call to a vtctld.
    93  	GetTablet = &cobra.Command{
    94  		Use:                   "GetTablet <alias>",
    95  		Short:                 "Outputs a JSON structure that contains information about the tablet.",
    96  		DisableFlagsInUseLine: true,
    97  		Args:                  cobra.ExactArgs(1),
    98  		RunE:                  commandGetTablet,
    99  	}
   100  	// GetTablets makes a GetTablets gRPC call to a vtctld.
   101  	GetTablets = &cobra.Command{
   102  		Use:   "GetTablets [--strict] [{--cell $c1 [--cell $c2 ...], --keyspace $ks [--shard $shard], --tablet-alias $alias}]",
   103  		Short: "Looks up tablets according to filter criteria.",
   104  		Long: `Looks up tablets according to the filter criteria.
   105  
   106  If --tablet-alias is passed, none of the other filters (keyspace, shard, cell) may
   107  be passed, and tablets are looked up by tablet alias only.
   108  
   109  If --keyspace is passed, then all tablets in the keyspace are retrieved. The
   110  --shard flag may also be passed to further narrow the set of tablets to that
   111  <keyspace/shard>. Passing --shard without also passing --keyspace will fail.
   112  
   113  Passing --cell limits the set of tablets to those in the specified cells. The
   114  --cell flag accepts a CSV argument (e.g. --cell "c1,c2") and may be repeated
   115  (e.g. --cell "c1" --cell "c2").
   116  
   117  Valid output formats are "awk" and "json".`,
   118  		DisableFlagsInUseLine: true,
   119  		Args:                  cobra.NoArgs,
   120  		RunE:                  commandGetTablets,
   121  	}
   122  	// GetTabletVersion makes a GetVersion RPC to a vtctld.
   123  	GetTabletVersion = &cobra.Command{
   124  		Use:                   "GetTabletVersion <alias>",
   125  		Short:                 "Print the version of a tablet from its debug vars.",
   126  		DisableFlagsInUseLine: true,
   127  		Aliases:               []string{"GetVersion"},
   128  		Args:                  cobra.ExactArgs(1),
   129  		RunE:                  commandGetTabletVersion,
   130  	}
   131  	// PingTablet makes a PingTablet gRPC call to a vtctld.
   132  	PingTablet = &cobra.Command{
   133  		Use:                   "PingTablet <alias>",
   134  		Short:                 "Checks that the specified tablet is awake and responding to RPCs. This command can be blocked by other in-flight operations.",
   135  		DisableFlagsInUseLine: true,
   136  		Args:                  cobra.ExactArgs(1),
   137  		RunE:                  commandPingTablet,
   138  	}
   139  	// RefreshState makes a RefreshState gRPC call to a vtctld.
   140  	RefreshState = &cobra.Command{
   141  		Use:                   "RefreshState <alias>",
   142  		Short:                 "Reloads the tablet record on the specified tablet.",
   143  		DisableFlagsInUseLine: true,
   144  		Args:                  cobra.ExactArgs(1),
   145  		RunE:                  commandRefreshState,
   146  	}
   147  	// RefreshStateByShard makes a RefreshStateByShard gRPC call to a vtcld.
   148  	RefreshStateByShard = &cobra.Command{
   149  		Use:                   "RefreshStateByShard [--cell <cell1> ...] <keyspace/shard>",
   150  		Short:                 "Reloads the tablet record all tablets in the shard, optionally limited to the specified cells.",
   151  		DisableFlagsInUseLine: true,
   152  		Args:                  cobra.ExactArgs(1),
   153  		RunE:                  commandRefreshStateByShard,
   154  	}
   155  	// RunHealthCheck makes a RunHealthCheck gRPC call to a vtctld.
   156  	RunHealthCheck = &cobra.Command{
   157  		Use:                   "RunHealthCheck <tablet_alias>",
   158  		Short:                 "Runs a healthcheck on the remote tablet.",
   159  		DisableFlagsInUseLine: true,
   160  		Aliases:               []string{"RunHealthcheck"},
   161  		Args:                  cobra.ExactArgs(1),
   162  		RunE:                  commandRunHealthCheck,
   163  	}
   164  	// SetWritable makes a SetWritable gRPC call to a vtctld.
   165  	SetWritable = &cobra.Command{
   166  		Use:                   "SetWritable <alias> <true/false>",
   167  		Short:                 "Sets the specified tablet as writable or read-only.",
   168  		DisableFlagsInUseLine: true,
   169  		Args:                  cobra.ExactArgs(2),
   170  		RunE:                  commandSetWritable,
   171  	}
   172  	// SleepTablet makes a SleepTablet gRPC call to a vtctld.
   173  	SleepTablet = &cobra.Command{
   174  		Use:   "SleepTablet <alias> <duration>",
   175  		Short: "Blocks the action queue on the specified tablet for the specified amount of time. This is typically used for testing.",
   176  		Long: `SleepTablet <alias> <duration>
   177  
   178  Blocks the action queue on the specified tablet for the specified duration.
   179  This command is typically only used for testing.
   180  		
   181  The duration is the amount of time that the action queue should be blocked.
   182  The value is a string that contains a possibly signed sequence of decimal numbers,
   183  each with optional fraction and a unit suffix, such as “300ms” or “1h45m”.
   184  See the definition of the Go language’s ParseDuration[1] function for more details.
   185  Note that, in the SleepTablet implementation, the value should be positively-signed.
   186  
   187  [1]: https://pkg.go.dev/time#ParseDuration
   188  `,
   189  		DisableFlagsInUseLine: true,
   190  		Args:                  cobra.ExactArgs(2),
   191  		RunE:                  commandSleepTablet,
   192  	}
   193  	// StartReplication makes a StartReplication gRPC call to a vtctld.
   194  	StartReplication = &cobra.Command{
   195  		Use:                   "StartReplication <alias>",
   196  		Short:                 "Starts replication on the specified tablet.",
   197  		DisableFlagsInUseLine: true,
   198  		Args:                  cobra.ExactArgs(1),
   199  		RunE:                  commandStartReplication,
   200  	}
   201  	// StopReplication makes a StopReplication gRPC call to a vtctld.
   202  	StopReplication = &cobra.Command{
   203  		Use:                   "StopReplication <alias>",
   204  		Short:                 "Stops replication on the specified tablet.",
   205  		DisableFlagsInUseLine: true,
   206  		Args:                  cobra.ExactArgs(1),
   207  		RunE:                  commandStopReplication,
   208  	}
   209  )
   210  
   211  var changeTabletTypeOptions = struct {
   212  	DryRun bool
   213  }{}
   214  
   215  func commandChangeTabletType(cmd *cobra.Command, args []string) error {
   216  	aliasStr := cmd.Flags().Arg(0)
   217  	typeStr := cmd.Flags().Arg(1)
   218  
   219  	alias, err := topoproto.ParseTabletAlias(aliasStr)
   220  	if err != nil {
   221  		return err
   222  	}
   223  
   224  	newType, err := topoproto.ParseTabletType(typeStr)
   225  	if err != nil {
   226  		return err
   227  	}
   228  
   229  	cli.FinishedParsing(cmd)
   230  
   231  	resp, err := client.ChangeTabletType(commandCtx, &vtctldatapb.ChangeTabletTypeRequest{
   232  		TabletAlias: alias,
   233  		DbType:      newType,
   234  		DryRun:      changeTabletTypeOptions.DryRun,
   235  	})
   236  	if err != nil {
   237  		return err
   238  	}
   239  
   240  	if resp.WasDryRun {
   241  		fmt.Println("--- DRY RUN ---")
   242  	}
   243  
   244  	fmt.Printf("- %v\n", cli.MarshalTabletAWK(resp.BeforeTablet))
   245  	fmt.Printf("+ %v\n", cli.MarshalTabletAWK(resp.AfterTablet))
   246  
   247  	return nil
   248  }
   249  
   250  var deleteTabletsOptions = struct {
   251  	AllowPrimary bool
   252  }{}
   253  
   254  func commandDeleteTablets(cmd *cobra.Command, args []string) error {
   255  	aliases, err := cli.TabletAliasesFromPosArgs(cmd.Flags().Args())
   256  	if err != nil {
   257  		return err
   258  	}
   259  
   260  	cli.FinishedParsing(cmd)
   261  
   262  	_, err = client.DeleteTablets(commandCtx, &vtctldatapb.DeleteTabletsRequest{
   263  		TabletAliases: aliases,
   264  		AllowPrimary:  deleteTabletsOptions.AllowPrimary,
   265  	})
   266  
   267  	if err != nil {
   268  		return fmt.Errorf("%w: while deleting %d tablets; please inspect the topo", err, len(aliases))
   269  	}
   270  
   271  	fmt.Printf("Successfully deleted %d tablets\n", len(aliases))
   272  
   273  	return nil
   274  }
   275  
   276  func commandExecuteHook(cmd *cobra.Command, args []string) error {
   277  	tabletAlias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   278  	if err != nil {
   279  		return err
   280  	}
   281  
   282  	hookName := cmd.Flags().Arg(1)
   283  	if strings.Contains(hookName, "/") {
   284  		return fmt.Errorf("cannot execute hook named %s, ExecuteHook does not support hook names with slashes ('/')", hookName)
   285  	}
   286  
   287  	cli.FinishedParsing(cmd)
   288  
   289  	hookParams := cmd.Flags().Args()[2:]
   290  	resp, err := client.ExecuteHook(commandCtx, &vtctldatapb.ExecuteHookRequest{
   291  		TabletAlias: tabletAlias,
   292  		TabletHookRequest: &tabletmanagerdatapb.ExecuteHookRequest{
   293  			Name:       hookName,
   294  			Parameters: hookParams,
   295  		},
   296  	})
   297  	if err != nil {
   298  		return err
   299  	}
   300  
   301  	data, err := cli.MarshalJSON(resp)
   302  	if err != nil {
   303  		return err
   304  	}
   305  
   306  	fmt.Printf("%s\n", data)
   307  	return nil
   308  }
   309  
   310  func commandGetFullStatus(cmd *cobra.Command, args []string) error {
   311  	aliasStr := cmd.Flags().Arg(0)
   312  	alias, err := topoproto.ParseTabletAlias(aliasStr)
   313  	if err != nil {
   314  		return err
   315  	}
   316  
   317  	cli.FinishedParsing(cmd)
   318  
   319  	resp, err := client.GetFullStatus(commandCtx, &vtctldatapb.GetFullStatusRequest{TabletAlias: alias})
   320  	if err != nil {
   321  		return err
   322  	}
   323  
   324  	data, err := cli.MarshalJSON(resp.Status)
   325  	if err != nil {
   326  		return err
   327  	}
   328  
   329  	fmt.Printf("%s\n", data)
   330  
   331  	return nil
   332  }
   333  
   334  func commandGetPermissions(cmd *cobra.Command, args []string) error {
   335  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   336  	if err != nil {
   337  		return err
   338  	}
   339  
   340  	cli.FinishedParsing(cmd)
   341  
   342  	resp, err := client.GetPermissions(commandCtx, &vtctldatapb.GetPermissionsRequest{
   343  		TabletAlias: alias,
   344  	})
   345  	if err != nil {
   346  		return err
   347  	}
   348  	p, err := cli.MarshalJSON(resp.Permissions)
   349  	if err != nil {
   350  		return err
   351  	}
   352  	fmt.Printf("%s\n", p)
   353  
   354  	return nil
   355  }
   356  
   357  func commandGetTablet(cmd *cobra.Command, args []string) error {
   358  	aliasStr := cmd.Flags().Arg(0)
   359  	alias, err := topoproto.ParseTabletAlias(aliasStr)
   360  	if err != nil {
   361  		return err
   362  	}
   363  
   364  	cli.FinishedParsing(cmd)
   365  
   366  	resp, err := client.GetTablet(commandCtx, &vtctldatapb.GetTabletRequest{TabletAlias: alias})
   367  	if err != nil {
   368  		return err
   369  	}
   370  
   371  	data, err := cli.MarshalJSON(resp.Tablet)
   372  	if err != nil {
   373  		return err
   374  	}
   375  
   376  	fmt.Printf("%s\n", data)
   377  
   378  	return nil
   379  }
   380  
   381  var getTabletsOptions = struct {
   382  	Cells    []string
   383  	Keyspace string
   384  	Shard    string
   385  
   386  	TabletAliasStrings []string
   387  
   388  	Format string
   389  	Strict bool
   390  }{}
   391  
   392  func commandGetTablets(cmd *cobra.Command, args []string) error {
   393  	format := strings.ToLower(getTabletsOptions.Format)
   394  
   395  	switch format {
   396  	case "awk", "json":
   397  	default:
   398  		return fmt.Errorf("invalid output format, got %s", getTabletsOptions.Format)
   399  	}
   400  
   401  	var aliases []*topodatapb.TabletAlias
   402  
   403  	if len(getTabletsOptions.TabletAliasStrings) > 0 {
   404  		switch {
   405  		case getTabletsOptions.Keyspace != "":
   406  			return fmt.Errorf("--keyspace (= %s) cannot be passed when using --tablet-alias (= %v)", getTabletsOptions.Keyspace, getTabletsOptions.TabletAliasStrings)
   407  		case getTabletsOptions.Shard != "":
   408  			return fmt.Errorf("--shard (= %s) cannot be passed when using --tablet-alias (= %v)", getTabletsOptions.Shard, getTabletsOptions.TabletAliasStrings)
   409  		case len(getTabletsOptions.Cells) > 0:
   410  			return fmt.Errorf("--cell (= %v) cannot be passed when using --tablet-alias (= %v)", getTabletsOptions.Cells, getTabletsOptions.TabletAliasStrings)
   411  		}
   412  
   413  		var err error
   414  		aliases, err = cli.TabletAliasesFromPosArgs(getTabletsOptions.TabletAliasStrings)
   415  		if err != nil {
   416  			return err
   417  		}
   418  	}
   419  
   420  	if getTabletsOptions.Keyspace == "" && getTabletsOptions.Shard != "" {
   421  		return fmt.Errorf("--shard (= %s) cannot be passed without also passing --keyspace", getTabletsOptions.Shard)
   422  	}
   423  
   424  	cli.FinishedParsing(cmd)
   425  
   426  	resp, err := client.GetTablets(commandCtx, &vtctldatapb.GetTabletsRequest{
   427  		TabletAliases: aliases,
   428  		Cells:         getTabletsOptions.Cells,
   429  		Keyspace:      getTabletsOptions.Keyspace,
   430  		Shard:         getTabletsOptions.Shard,
   431  		Strict:        getTabletsOptions.Strict,
   432  	})
   433  	if err != nil {
   434  		return err
   435  	}
   436  
   437  	switch format {
   438  	case "awk":
   439  		for _, t := range resp.Tablets {
   440  			fmt.Println(cli.MarshalTabletAWK(t))
   441  		}
   442  	case "json":
   443  		data, err := cli.MarshalJSON(resp.Tablets)
   444  		if err != nil {
   445  			return err
   446  		}
   447  
   448  		fmt.Printf("%s\n", data)
   449  	}
   450  
   451  	return nil
   452  }
   453  
   454  func commandGetTabletVersion(cmd *cobra.Command, args []string) error {
   455  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   456  	if err != nil {
   457  		return err
   458  	}
   459  
   460  	cli.FinishedParsing(cmd)
   461  
   462  	resp, err := client.GetVersion(commandCtx, &vtctldatapb.GetVersionRequest{
   463  		TabletAlias: alias,
   464  	})
   465  	if err != nil {
   466  		return err
   467  	}
   468  
   469  	fmt.Println(resp.Version)
   470  	return nil
   471  }
   472  
   473  func commandPingTablet(cmd *cobra.Command, args []string) error {
   474  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   475  	if err != nil {
   476  		return err
   477  	}
   478  
   479  	cli.FinishedParsing(cmd)
   480  
   481  	_, err = client.PingTablet(commandCtx, &vtctldatapb.PingTabletRequest{
   482  		TabletAlias: alias,
   483  	})
   484  	return err
   485  }
   486  
   487  func commandRefreshState(cmd *cobra.Command, args []string) error {
   488  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   489  	if err != nil {
   490  		return err
   491  	}
   492  
   493  	cli.FinishedParsing(cmd)
   494  
   495  	_, err = client.RefreshState(commandCtx, &vtctldatapb.RefreshStateRequest{
   496  		TabletAlias: alias,
   497  	})
   498  	if err != nil {
   499  		return err
   500  	}
   501  
   502  	fmt.Printf("Refreshed state on %s\n", topoproto.TabletAliasString(alias))
   503  	return nil
   504  }
   505  
   506  var refreshStateByShardOptions = struct {
   507  	Cells []string
   508  }{}
   509  
   510  func commandRefreshStateByShard(cmd *cobra.Command, args []string) error {
   511  	keyspace, shard, err := topoproto.ParseKeyspaceShard(cmd.Flags().Arg(0))
   512  	if err != nil {
   513  		return err
   514  	}
   515  
   516  	cli.FinishedParsing(cmd)
   517  
   518  	resp, err := client.RefreshStateByShard(commandCtx, &vtctldatapb.RefreshStateByShardRequest{
   519  		Keyspace: keyspace,
   520  		Shard:    shard,
   521  		Cells:    refreshStateByShardOptions.Cells,
   522  	})
   523  	if err != nil {
   524  		return err
   525  	}
   526  
   527  	msg := &strings.Builder{}
   528  	msg.WriteString(fmt.Sprintf("Refreshed state on %s/%s", keyspace, shard))
   529  	if len(refreshStateByShardOptions.Cells) > 0 {
   530  		msg.WriteString(fmt.Sprintf(" in cells %s", strings.Join(refreshStateByShardOptions.Cells, ", ")))
   531  	}
   532  	msg.WriteByte('\n')
   533  	if resp.IsPartialRefresh {
   534  		msg.WriteString("State refresh was partial; some tablets in the shard may not have succeeded.\n")
   535  	}
   536  
   537  	fmt.Print(msg.String())
   538  	return nil
   539  }
   540  
   541  func commandRunHealthCheck(cmd *cobra.Command, args []string) error {
   542  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   543  	if err != nil {
   544  		return err
   545  	}
   546  
   547  	cli.FinishedParsing(cmd)
   548  
   549  	_, err = client.RunHealthCheck(commandCtx, &vtctldatapb.RunHealthCheckRequest{
   550  		TabletAlias: alias,
   551  	})
   552  	return err
   553  }
   554  
   555  func commandSetWritable(cmd *cobra.Command, args []string) error {
   556  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   557  	if err != nil {
   558  		return err
   559  	}
   560  
   561  	isWritable, err := strconv.ParseBool(cmd.Flags().Arg(1))
   562  	if err != nil {
   563  		return err
   564  	}
   565  
   566  	cli.FinishedParsing(cmd)
   567  
   568  	_, err = client.SetWritable(commandCtx, &vtctldatapb.SetWritableRequest{
   569  		TabletAlias: alias,
   570  		Writable:    isWritable,
   571  	})
   572  	return err
   573  }
   574  
   575  func commandSleepTablet(cmd *cobra.Command, args []string) error {
   576  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   577  	if err != nil {
   578  		return err
   579  	}
   580  
   581  	duration, err := time.ParseDuration(cmd.Flags().Arg(1))
   582  	if err != nil {
   583  		return err
   584  	}
   585  
   586  	cli.FinishedParsing(cmd)
   587  
   588  	_, err = client.SleepTablet(commandCtx, &vtctldatapb.SleepTabletRequest{
   589  		TabletAlias: alias,
   590  		Duration:    protoutil.DurationToProto(duration),
   591  	})
   592  	return err
   593  }
   594  
   595  func commandStartReplication(cmd *cobra.Command, args []string) error {
   596  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   597  	if err != nil {
   598  		return err
   599  	}
   600  
   601  	cli.FinishedParsing(cmd)
   602  
   603  	_, err = client.StartReplication(commandCtx, &vtctldatapb.StartReplicationRequest{
   604  		TabletAlias: alias,
   605  	})
   606  	return err
   607  }
   608  
   609  func commandStopReplication(cmd *cobra.Command, args []string) error {
   610  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   611  	if err != nil {
   612  		return err
   613  	}
   614  
   615  	cli.FinishedParsing(cmd)
   616  
   617  	_, err = client.StopReplication(commandCtx, &vtctldatapb.StopReplicationRequest{
   618  		TabletAlias: alias,
   619  	})
   620  	return err
   621  }
   622  
   623  func init() {
   624  	ChangeTabletType.Flags().BoolVarP(&changeTabletTypeOptions.DryRun, "dry-run", "d", false, "Shows the proposed change without actually executing it.")
   625  	Root.AddCommand(ChangeTabletType)
   626  
   627  	DeleteTablets.Flags().BoolVarP(&deleteTabletsOptions.AllowPrimary, "allow-primary", "p", false, "Allow the primary tablet of a shard to be deleted. Use with caution.")
   628  	Root.AddCommand(DeleteTablets)
   629  
   630  	Root.AddCommand(ExecuteHook)
   631  	Root.AddCommand(GetFullStatus)
   632  	Root.AddCommand(GetPermissions)
   633  	Root.AddCommand(GetTablet)
   634  
   635  	GetTablets.Flags().StringSliceVarP(&getTabletsOptions.TabletAliasStrings, "tablet-alias", "t", nil, "List of tablet aliases to filter by.")
   636  	GetTablets.Flags().StringSliceVarP(&getTabletsOptions.Cells, "cell", "c", nil, "List of cells to filter tablets by.")
   637  	GetTablets.Flags().StringVarP(&getTabletsOptions.Keyspace, "keyspace", "k", "", "Keyspace to filter tablets by.")
   638  	GetTablets.Flags().StringVarP(&getTabletsOptions.Shard, "shard", "s", "", "Shard to filter tablets by.")
   639  	GetTablets.Flags().StringVar(&getTabletsOptions.Format, "format", "awk", "Output format to use; valid choices are (json, awk).")
   640  	GetTablets.Flags().BoolVar(&getTabletsOptions.Strict, "strict", false, "Require all cells to return successful tablet data. Without --strict, tablet listings may be partial.")
   641  	Root.AddCommand(GetTablets)
   642  
   643  	Root.AddCommand(GetTabletVersion)
   644  	Root.AddCommand(PingTablet)
   645  	Root.AddCommand(RefreshState)
   646  
   647  	RefreshStateByShard.Flags().StringSliceVarP(&refreshStateByShardOptions.Cells, "cells", "c", nil, "If specified, only call RefreshState on tablets in the specified cells. If empty, all cells are considered.")
   648  	Root.AddCommand(RefreshStateByShard)
   649  
   650  	Root.AddCommand(RunHealthCheck)
   651  	Root.AddCommand(SetWritable)
   652  	Root.AddCommand(SleepTablet)
   653  	Root.AddCommand(StartReplication)
   654  	Root.AddCommand(StopReplication)
   655  }