vitess.io/vitess@v0.16.2/go/cmd/vtctldclient/command/reparents.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  	"time"
    22  
    23  	"github.com/spf13/cobra"
    24  
    25  	"vitess.io/vitess/go/cmd/vtctldclient/cli"
    26  	"vitess.io/vitess/go/protoutil"
    27  	"vitess.io/vitess/go/vt/log"
    28  	"vitess.io/vitess/go/vt/logutil"
    29  	"vitess.io/vitess/go/vt/topo"
    30  	"vitess.io/vitess/go/vt/topo/topoproto"
    31  
    32  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    33  	vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata"
    34  )
    35  
    36  var (
    37  	// EmergencyReparentShard makes an EmergencyReparent gRPC call to a vtctld.
    38  	EmergencyReparentShard = &cobra.Command{
    39  		Use:                   "EmergencyReparentShard <keyspace/shard>",
    40  		Short:                 "Reparents the shard to the new primary. Assumes the old primary is dead and not responding.",
    41  		DisableFlagsInUseLine: true,
    42  		Args:                  cobra.ExactArgs(1),
    43  		RunE:                  commandEmergencyReparentShard,
    44  	}
    45  	// InitShardPrimary makes an InitShardPrimary gRPC call to a vtctld.
    46  	InitShardPrimary = &cobra.Command{
    47  		Use:   "InitShardPrimary <keyspace/shard> <primary alias>",
    48  		Short: "Sets the initial primary for the shard.",
    49  		Long: `Sets the initial primary for the shard.
    50  
    51  This will make all other tablets in the shard become replicas of the promoted tablet.
    52  WARNING: this can cause data loss on an already-replicating shard. PlannedReparentShard or
    53  EmergencyReparentShard should be used instead.
    54  `,
    55  		DisableFlagsInUseLine: true,
    56  		Deprecated:            "Please use PlannedReparentShard instead",
    57  		Args:                  cobra.ExactArgs(2),
    58  		RunE:                  commandInitShardPrimary,
    59  	}
    60  	// PlannedReparentShard makes a PlannedReparentShard gRPC call to a vtctld.
    61  	PlannedReparentShard = &cobra.Command{
    62  		Use:                   "PlannedReparentShard <keyspace/shard>",
    63  		Short:                 "Reparents the shard to a new primary, or away from an old primary. Both the old and new primaries must be up and running.",
    64  		DisableFlagsInUseLine: true,
    65  		Args:                  cobra.ExactArgs(1),
    66  		RunE:                  commandPlannedReparentShard,
    67  	}
    68  	// ReparentTablet makes a ReparentTablet gRPC call to a vtctld.
    69  	ReparentTablet = &cobra.Command{
    70  		Use:                   "ReparentTablet <alias>",
    71  		Short:                 "Reparent a tablet to the current primary in the shard.",
    72  		DisableFlagsInUseLine: true,
    73  		Args:                  cobra.ExactArgs(1),
    74  		RunE:                  commandReparentTablet,
    75  	}
    76  	// TabletExternallyReparented makes a TabletExternallyReparented gRPC call
    77  	// to a vtctld.
    78  	TabletExternallyReparented = &cobra.Command{
    79  		Use:   "TabletExternallyReparented <alias>",
    80  		Short: "Updates the topology record for the tablet's shard to acknowledge that an external tool made this tablet the primary.",
    81  		Long: `Updates the topology record for the tablet's shard to acknowledge that an external tool made this tablet the primary.
    82  
    83  See the Reparenting guide for more information: https://vitess.io/docs/user-guides/reparenting/#external-reparenting.
    84  `,
    85  		DisableFlagsInUseLine: true,
    86  		Args:                  cobra.ExactArgs(1),
    87  		RunE:                  commandTabletExternallyReparented,
    88  	}
    89  )
    90  
    91  var emergencyReparentShardOptions = struct {
    92  	Force                     bool
    93  	WaitReplicasTimeout       time.Duration
    94  	NewPrimaryAliasStr        string
    95  	IgnoreReplicaAliasStrList []string
    96  	PreventCrossCellPromotion bool
    97  }{}
    98  
    99  func commandEmergencyReparentShard(cmd *cobra.Command, args []string) error {
   100  	keyspace, shard, err := topoproto.ParseKeyspaceShard(cmd.Flags().Arg(0))
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	var (
   106  		newPrimaryAlias      *topodatapb.TabletAlias
   107  		ignoreReplicaAliases = make([]*topodatapb.TabletAlias, len(emergencyReparentShardOptions.IgnoreReplicaAliasStrList))
   108  	)
   109  
   110  	if emergencyReparentShardOptions.NewPrimaryAliasStr != "" {
   111  		newPrimaryAlias, err = topoproto.ParseTabletAlias(emergencyReparentShardOptions.NewPrimaryAliasStr)
   112  		if err != nil {
   113  			return err
   114  		}
   115  	}
   116  
   117  	for i, aliasStr := range emergencyReparentShardOptions.IgnoreReplicaAliasStrList {
   118  		alias, err := topoproto.ParseTabletAlias(aliasStr)
   119  		if err != nil {
   120  			return err
   121  		}
   122  
   123  		ignoreReplicaAliases[i] = alias
   124  	}
   125  
   126  	cli.FinishedParsing(cmd)
   127  
   128  	resp, err := client.EmergencyReparentShard(commandCtx, &vtctldatapb.EmergencyReparentShardRequest{
   129  		Keyspace:                  keyspace,
   130  		Shard:                     shard,
   131  		NewPrimary:                newPrimaryAlias,
   132  		IgnoreReplicas:            ignoreReplicaAliases,
   133  		WaitReplicasTimeout:       protoutil.DurationToProto(emergencyReparentShardOptions.WaitReplicasTimeout),
   134  		PreventCrossCellPromotion: emergencyReparentShardOptions.PreventCrossCellPromotion,
   135  	})
   136  	if err != nil {
   137  		return err
   138  	}
   139  
   140  	for _, event := range resp.Events {
   141  		fmt.Println(logutil.EventString(event))
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  var initShardPrimaryOptions = struct {
   148  	WaitReplicasTimeout time.Duration
   149  	Force               bool
   150  }{}
   151  
   152  func commandInitShardPrimary(cmd *cobra.Command, args []string) error {
   153  	keyspace, shard, err := topoproto.ParseKeyspaceShard(cmd.Flags().Arg(0))
   154  	if err != nil {
   155  		return err
   156  	}
   157  
   158  	tabletAlias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(1))
   159  	if err != nil {
   160  		return err
   161  	}
   162  
   163  	cli.FinishedParsing(cmd)
   164  
   165  	resp, err := client.InitShardPrimary(commandCtx, &vtctldatapb.InitShardPrimaryRequest{
   166  		Keyspace:                keyspace,
   167  		Shard:                   shard,
   168  		PrimaryElectTabletAlias: tabletAlias,
   169  		WaitReplicasTimeout:     protoutil.DurationToProto(initShardPrimaryOptions.WaitReplicasTimeout),
   170  		Force:                   initShardPrimaryOptions.Force,
   171  	})
   172  	if err != nil {
   173  		return err
   174  	}
   175  
   176  	for _, event := range resp.Events {
   177  		log.Infof("%v", event)
   178  	}
   179  
   180  	return err
   181  }
   182  
   183  var plannedReparentShardOptions = struct {
   184  	NewPrimaryAliasStr   string
   185  	AvoidPrimaryAliasStr string
   186  	WaitReplicasTimeout  time.Duration
   187  }{}
   188  
   189  func commandPlannedReparentShard(cmd *cobra.Command, args []string) error {
   190  	keyspace, shard, err := topoproto.ParseKeyspaceShard(cmd.Flags().Arg(0))
   191  	if err != nil {
   192  		return err
   193  	}
   194  
   195  	var (
   196  		newPrimaryAlias   *topodatapb.TabletAlias
   197  		avoidPrimaryAlias *topodatapb.TabletAlias
   198  	)
   199  
   200  	if plannedReparentShardOptions.NewPrimaryAliasStr != "" {
   201  		newPrimaryAlias, err = topoproto.ParseTabletAlias(plannedReparentShardOptions.NewPrimaryAliasStr)
   202  		if err != nil {
   203  			return err
   204  		}
   205  	}
   206  
   207  	if plannedReparentShardOptions.AvoidPrimaryAliasStr != "" {
   208  		avoidPrimaryAlias, err = topoproto.ParseTabletAlias(plannedReparentShardOptions.AvoidPrimaryAliasStr)
   209  		if err != nil {
   210  			return err
   211  		}
   212  	}
   213  
   214  	cli.FinishedParsing(cmd)
   215  
   216  	resp, err := client.PlannedReparentShard(commandCtx, &vtctldatapb.PlannedReparentShardRequest{
   217  		Keyspace:            keyspace,
   218  		Shard:               shard,
   219  		NewPrimary:          newPrimaryAlias,
   220  		AvoidPrimary:        avoidPrimaryAlias,
   221  		WaitReplicasTimeout: protoutil.DurationToProto(plannedReparentShardOptions.WaitReplicasTimeout),
   222  	})
   223  	if err != nil {
   224  		return err
   225  	}
   226  
   227  	for _, event := range resp.Events {
   228  		fmt.Println(logutil.EventString(event))
   229  	}
   230  
   231  	return nil
   232  }
   233  
   234  func commandReparentTablet(cmd *cobra.Command, args []string) error {
   235  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   236  	if err != nil {
   237  		return err
   238  	}
   239  
   240  	resp, err := client.ReparentTablet(commandCtx, &vtctldatapb.ReparentTabletRequest{
   241  		Tablet: alias,
   242  	})
   243  	if err != nil {
   244  		return err
   245  	}
   246  
   247  	data, err := cli.MarshalJSON(resp)
   248  	if err != nil {
   249  		return err
   250  	}
   251  
   252  	fmt.Printf("%s\n", data)
   253  
   254  	return nil
   255  }
   256  
   257  func commandTabletExternallyReparented(cmd *cobra.Command, args []string) error {
   258  	alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0))
   259  	if err != nil {
   260  		return err
   261  	}
   262  
   263  	resp, err := client.TabletExternallyReparented(commandCtx, &vtctldatapb.TabletExternallyReparentedRequest{
   264  		Tablet: alias,
   265  	})
   266  	if err != nil {
   267  		return err
   268  	}
   269  
   270  	data, err := cli.MarshalJSON(resp)
   271  	if err != nil {
   272  		return err
   273  	}
   274  
   275  	fmt.Printf("%s\n", data)
   276  
   277  	return nil
   278  }
   279  
   280  func init() {
   281  	EmergencyReparentShard.Flags().DurationVar(&emergencyReparentShardOptions.WaitReplicasTimeout, "wait-replicas-timeout", topo.RemoteOperationTimeout, "Time to wait for replicas to catch up in reparenting.")
   282  	EmergencyReparentShard.Flags().StringVar(&emergencyReparentShardOptions.NewPrimaryAliasStr, "new-primary", "", "Alias of a tablet that should be the new primary. If not specified, the vtctld will select the best candidate to promote.")
   283  	EmergencyReparentShard.Flags().BoolVar(&emergencyReparentShardOptions.PreventCrossCellPromotion, "prevent-cross-cell-promotion", false, "Only promotes a new primary from the same cell as the previous primary.")
   284  	EmergencyReparentShard.Flags().StringSliceVarP(&emergencyReparentShardOptions.IgnoreReplicaAliasStrList, "ignore-replicas", "i", nil, "Comma-separated, repeated list of replica tablet aliases to ignore during the emergency reparent.")
   285  	Root.AddCommand(EmergencyReparentShard)
   286  
   287  	InitShardPrimary.Flags().DurationVar(&initShardPrimaryOptions.WaitReplicasTimeout, "wait-replicas-timeout", 30*time.Second, "Time to wait for replicas to catch up in reparenting.")
   288  	InitShardPrimary.Flags().BoolVar(&initShardPrimaryOptions.Force, "force", false, "Force the reparent even if the provided tablet is not writable or the shard primary.")
   289  	Root.AddCommand(InitShardPrimary)
   290  
   291  	PlannedReparentShard.Flags().DurationVar(&plannedReparentShardOptions.WaitReplicasTimeout, "wait-replicas-timeout", topo.RemoteOperationTimeout, "Time to wait for replicas to catch up on replication both before and after reparenting.")
   292  	PlannedReparentShard.Flags().StringVar(&plannedReparentShardOptions.NewPrimaryAliasStr, "new-primary", "", "Alias of a tablet that should be the new primary.")
   293  	PlannedReparentShard.Flags().StringVar(&plannedReparentShardOptions.AvoidPrimaryAliasStr, "avoid-primary", "", "Alias of a tablet that should not be the primary; i.e. \"reparent to any other tablet if this one is the primary\".")
   294  	Root.AddCommand(PlannedReparentShard)
   295  
   296  	Root.AddCommand(ReparentTablet)
   297  	Root.AddCommand(TabletExternallyReparented)
   298  }