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  }