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 }