vitess.io/vitess@v0.16.2/go/cmd/vtctldclient/command/backups.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 "io" 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/mysqlctl" 30 "vitess.io/vitess/go/vt/topo/topoproto" 31 32 vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata" 33 ) 34 35 var ( 36 // Backup makes a Backup gRPC call to a vtctld. 37 Backup = &cobra.Command{ 38 Use: "Backup [--concurrency <concurrency>] [--allow-primary] <tablet_alias>", 39 Short: "Uses the BackupStorage service on the given tablet to create and store a new backup.", 40 DisableFlagsInUseLine: true, 41 Args: cobra.ExactArgs(1), 42 RunE: commandBackup, 43 } 44 // BackupShard makes a BackupShard gRPC call to a vtctld. 45 BackupShard = &cobra.Command{ 46 Use: "BackupShard [--concurrency <concurrency>] [--allow-primary] <keyspace/shard>", 47 Short: "Finds the most up-to-date REPLICA, RDONLY, or SPARE tablet in the given shard and uses the BackupStorage service on that tablet to create and store a new backup.", 48 Long: `Finds the most up-to-date REPLICA, RDONLY, or SPARE tablet in the given shard and uses the BackupStorage service on that tablet to create and store a new backup. 49 50 If no replica-type tablet can be found, the backup can be taken on the primary if --allow-primary is specified.`, 51 DisableFlagsInUseLine: true, 52 Args: cobra.ExactArgs(1), 53 RunE: commandBackupShard, 54 } 55 // GetBackups makes a GetBackups gRPC call to a vtctld. 56 GetBackups = &cobra.Command{ 57 Use: "GetBackups [--limit <limit>] [--json] <keyspace/shard>", 58 Short: "Lists backups for the given shard.", 59 DisableFlagsInUseLine: true, 60 Args: cobra.ExactArgs(1), 61 RunE: commandGetBackups, 62 } 63 // RemoveBackup makes a RemoveBackup gRPC call to a vtctld. 64 RemoveBackup = &cobra.Command{ 65 Use: "RemoveBackup <keyspace/shard> <backup name>", 66 Short: "Removes the given backup from the BackupStorage used by vtctld.", 67 DisableFlagsInUseLine: true, 68 Args: cobra.ExactArgs(2), 69 RunE: commandRemoveBackup, 70 } 71 // RestoreFromBackup makes a RestoreFromBackup gRPC call to a vtctld. 72 RestoreFromBackup = &cobra.Command{ 73 Use: "RestoreFromBackup [--backup-timestamp|-t <YYYY-mm-DD.HHMMSS>] <tablet_alias>", 74 Short: "Stops mysqld on the specified tablet and restores the data from either the latest backup or closest before `backup-timestamp`.", 75 DisableFlagsInUseLine: true, 76 Args: cobra.ExactArgs(1), 77 RunE: commandRestoreFromBackup, 78 } 79 ) 80 81 var backupOptions = struct { 82 AllowPrimary bool 83 Concurrency uint64 84 }{} 85 86 func commandBackup(cmd *cobra.Command, args []string) error { 87 tabletAlias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0)) 88 if err != nil { 89 return err 90 } 91 92 cli.FinishedParsing(cmd) 93 94 stream, err := client.Backup(commandCtx, &vtctldatapb.BackupRequest{ 95 TabletAlias: tabletAlias, 96 AllowPrimary: backupOptions.AllowPrimary, 97 Concurrency: backupOptions.Concurrency, 98 }) 99 if err != nil { 100 return err 101 } 102 103 for { 104 resp, err := stream.Recv() 105 switch err { 106 case nil: 107 fmt.Printf("%s/%s (%s): %v\n", resp.Keyspace, resp.Shard, topoproto.TabletAliasString(resp.TabletAlias), resp.Event) 108 case io.EOF: 109 return nil 110 default: 111 return err 112 } 113 } 114 } 115 116 var backupShardOptions = struct { 117 AllowPrimary bool 118 Concurrency uint64 119 }{} 120 121 func commandBackupShard(cmd *cobra.Command, args []string) error { 122 keyspace, shard, err := topoproto.ParseKeyspaceShard(cmd.Flags().Arg(0)) 123 if err != nil { 124 return err 125 } 126 127 cli.FinishedParsing(cmd) 128 129 stream, err := client.BackupShard(commandCtx, &vtctldatapb.BackupShardRequest{ 130 Keyspace: keyspace, 131 Shard: shard, 132 AllowPrimary: backupOptions.AllowPrimary, 133 Concurrency: backupOptions.Concurrency, 134 }) 135 if err != nil { 136 return err 137 } 138 139 for { 140 resp, err := stream.Recv() 141 switch err { 142 case nil: 143 fmt.Printf("%s/%s (%s): %v\n", resp.Keyspace, resp.Shard, topoproto.TabletAliasString(resp.TabletAlias), resp.Event) 144 case io.EOF: 145 return nil 146 default: 147 return err 148 } 149 } 150 } 151 152 var getBackupsOptions = struct { 153 Limit uint32 154 OutputJSON bool 155 }{} 156 157 func commandGetBackups(cmd *cobra.Command, args []string) error { 158 keyspace, shard, err := topoproto.ParseKeyspaceShard(cmd.Flags().Arg(0)) 159 if err != nil { 160 return err 161 } 162 163 cli.FinishedParsing(cmd) 164 165 resp, err := client.GetBackups(commandCtx, &vtctldatapb.GetBackupsRequest{ 166 Keyspace: keyspace, 167 Shard: shard, 168 Limit: getBackupsOptions.Limit, 169 }) 170 if err != nil { 171 return err 172 } 173 174 if getBackupsOptions.OutputJSON { 175 data, err := cli.MarshalJSON(resp) 176 if err != nil { 177 return err 178 } 179 180 fmt.Printf("%s\n", data) 181 return nil 182 } 183 184 names := make([]string, len(resp.Backups)) 185 for i, b := range resp.Backups { 186 names[i] = b.Name 187 } 188 189 fmt.Printf("%s\n", strings.Join(names, "\n")) 190 191 return nil 192 } 193 194 func commandRemoveBackup(cmd *cobra.Command, args []string) error { 195 keyspace, shard, err := topoproto.ParseKeyspaceShard(cmd.Flags().Arg(0)) 196 if err != nil { 197 return err 198 } 199 200 name := cmd.Flags().Arg(1) 201 202 cli.FinishedParsing(cmd) 203 204 _, err = client.RemoveBackup(commandCtx, &vtctldatapb.RemoveBackupRequest{ 205 Keyspace: keyspace, 206 Shard: shard, 207 Name: name, 208 }) 209 return err 210 } 211 212 var restoreFromBackupOptions = struct { 213 BackupTimestamp string 214 }{} 215 216 func commandRestoreFromBackup(cmd *cobra.Command, args []string) error { 217 alias, err := topoproto.ParseTabletAlias(cmd.Flags().Arg(0)) 218 if err != nil { 219 return err 220 } 221 222 req := &vtctldatapb.RestoreFromBackupRequest{ 223 TabletAlias: alias, 224 } 225 226 if restoreFromBackupOptions.BackupTimestamp != "" { 227 t, err := time.Parse(mysqlctl.BackupTimestampFormat, restoreFromBackupOptions.BackupTimestamp) 228 if err != nil { 229 return err 230 } 231 232 req.BackupTime = protoutil.TimeToProto(t) 233 } 234 235 cli.FinishedParsing(cmd) 236 237 stream, err := client.RestoreFromBackup(commandCtx, req) 238 if err != nil { 239 return err 240 } 241 242 for { 243 resp, err := stream.Recv() 244 switch err { 245 case nil: 246 fmt.Printf("%s/%s (%s): %v\n", resp.Keyspace, resp.Shard, topoproto.TabletAliasString(resp.TabletAlias), resp.Event) 247 case io.EOF: 248 return nil 249 default: 250 return err 251 } 252 } 253 } 254 255 func init() { 256 Backup.Flags().BoolVar(&backupOptions.AllowPrimary, "allow-primary", false, "Allow the primary of a shard to be used for the backup. WARNING: If using the builtin backup engine, this will shutdown mysqld on the primary and stop writes for the duration of the backup.") 257 Backup.Flags().Uint64Var(&backupOptions.Concurrency, "concurrency", 4, "Specifies the number of compression/checksum jobs to run simultaneously.") 258 Root.AddCommand(Backup) 259 260 BackupShard.Flags().BoolVar(&backupShardOptions.AllowPrimary, "allow-primary", false, "Allow the primary of a shard to be used for the backup. WARNING: If using the builtin backup engine, this will shutdown mysqld on the primary and stop writes for the duration of the backup.") 261 BackupShard.Flags().Uint64Var(&backupShardOptions.Concurrency, "concurrency", 4, "Specifies the number of compression/checksum jobs to run simultaneously.") 262 Root.AddCommand(BackupShard) 263 264 GetBackups.Flags().Uint32VarP(&getBackupsOptions.Limit, "limit", "l", 0, "Retrieve only the most recent N backups.") 265 GetBackups.Flags().BoolVarP(&getBackupsOptions.OutputJSON, "json", "j", false, "Output backup info in JSON format rather than a list of backups.") 266 Root.AddCommand(GetBackups) 267 268 Root.AddCommand(RemoveBackup) 269 270 RestoreFromBackup.Flags().StringVarP(&restoreFromBackupOptions.BackupTimestamp, "backup-timestamp", "t", "", "Use the backup taken at, or closest before, this timestamp. Omit to use the latest backup. Timestamp format is \"YYYY-mm-DD.HHMMSS\".") 271 Root.AddCommand(RestoreFromBackup) 272 }