-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
select backup engine in Backup() and ignore engines in RestoreFromBackup() #16428
Conversation
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Review ChecklistHello reviewers! 👋 Please follow this checklist when reviewing this Pull Request. General
Tests
Documentation
New flags
If a workflow is added or modified:
Backward compatibility
|
Backup()
and ignore engines in RestoreFromBackup()
Backup()
and ignore engines in RestoreFromBackup()
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #16428 +/- ##
==========================================
+ Coverage 69.44% 69.45% +0.01%
==========================================
Files 1571 1571
Lines 203004 203021 +17
==========================================
+ Hits 140974 141013 +39
+ Misses 62030 62008 -22 ☔ View full report in Codecov by Sentry. |
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
…ackup Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this, I've left a few comments throughout the code.
Some major points:
cluster_endtoend_vtctlbackup_sharded_clustertest_heavy.yml
may not be modified into usingxtrabackup
because this means we're losing trust in Vitess' functionality on vanilla MySQL.- Also, this is (as the name suggests) on of the heaviest
endtoend
tests we have; consider creating a new and shorter test. - Like @deepthi , I prefer allow lists over deny lists. If there's a strong argument for deny lists, please let us know. But IMO if next week someone introduces a new backup method which does not match your requirements, you have to rush to edit your deployment/scripts/tools to ensure it's not being used. Whereas if next week someone introduces a new backup method which does comply with your requirements, then you can at leisure add it.
- Let's use meaningful data in tests, and more explicit tests over such data.
@@ -299,6 +312,7 @@ func init() { | |||
Root.AddCommand(RemoveBackup) | |||
|
|||
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\".") | |||
RestoreFromBackup.Flags().StringVar(&restoreFromBackupOptions.IgnoredBackupEngines, "ignored-backup-engines", "", "Ignore backups created with this list of backup engines, sepparated by a comma") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a StringSliceVar
flag type that handles comma separated lists.
lastBackup := getLastBackup(t) | ||
|
||
// open the Manifest and retrieve the backup engine that was used | ||
f, err := os.Open(path.Join(localCluster.CurrentVTDATAROOT, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an existing readManifestFile()
function in backup_utils.go
. Please reuse.
return manifest.BackupMethod | ||
} | ||
|
||
func getLastBackup(t *testing.T) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider reusing (or refactoring) func (cluster LocalProcessCluster) ListBackups(shardKsName string) ([]string, error)
// lets take two backups, each using a different backup engine | ||
err = localCluster.VtctldClientProcess.ExecuteCommand("Backup", "--allow-primary", "--backup-engine=builtin", primary.Alias) | ||
require.NoError(t, err) | ||
// firstBackup := getLastBackup(t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the above line?
// check the new replica has the data | ||
cluster.VerifyRowsInTablet(t, replica2, keyspaceName, 2) | ||
|
||
// now lets break the last backup in the shard |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are different tests here. Please separate them via properly named t.Run(..., )
subtests.
// make sure we are replicating after the restore is done | ||
err = replica2.VttabletProcess.WaitForTabletStatusesForTimeout([]string{"SERVING"}, timeout) | ||
require.NoError(t, err) | ||
cluster.VerifyRowsInTablet(t, replica2, keyspaceName, 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cluster.VerifyRowsInTablet
is a valid way to test the restore content, and strong enough as the test goes, but not clear enough for future us. It's better to explicitly require "there's a row with this specific string value that means something".
go/vt/mysqlctl/backupengine.go
Outdated
@@ -213,8 +219,14 @@ func registerBackupEngineFlags(fs *pflag.FlagSet) { | |||
// a particular backup by calling GetRestoreEngine(). | |||
// | |||
// This must only be called after flags have been parsed. | |||
func GetBackupEngine() (BackupEngine, error) { | |||
name := backupEngineImplementation | |||
func GetBackupEngine(backupEngine *string) (BackupEngine, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's never pass a *string
. This function should accept a string
. If it's empty, use the default value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the reason it is a *string
is because that's how grpc optional arguments are created (as it should avoid backward compatibility issues). just to confirm, you prefer me to get rid of it completely and make it mandatory or just avoid passing a *string
to GetBackupEngine()
? I will keep the grpc optional parameter for now, but let me know if you prefer the other way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or just avoid passing a *string to GetBackupEngine()
This.
go/vt/mysqlctl/backupengine.go
Outdated
var name string | ||
if backupEngine == nil || *backupEngine == "" { | ||
name = backupEngineImplementation | ||
} else { | ||
name = *backupEngine | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this more canonical (and also more idiomatic):
var name string | |
if backupEngine == nil || *backupEngine == "" { | |
name = backupEngineImplementation | |
} else { | |
name = *backupEngine | |
} | |
name := backupEngineImplementation | |
if backupEngine != "" { | |
name = backupEngine | |
} |
|
||
statsRestoreBackupTime *stats.String | ||
statsRestoreBackupPosition *stats.String | ||
) | ||
|
||
func registerRestoreFlags(fs *pflag.FlagSet) { | ||
fs.BoolVar(&restoreFromBackup, "restore_from_backup", restoreFromBackup, "(init restore parameter) will check BackupStorage for a recent backup at startup and start there") | ||
fs.StringVar(&restoreFromBackupIgnoreEngines, "restore_from_backup_ignore_engines", restoreFromBackupIgnoreEngines, "ignore backups taken with the backup engines provided in this comma-separated list") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use StringSliceVar
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
@shlomi-noach @deepthi thanks again for the review! I believe I have addressed all your comments, but let me know if I missed anything. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good now except for the flag name and help text. I can approve once those are fixed.
go/flags/endtoend/vttablet.txt
Outdated
@@ -300,6 +300,7 @@ Flags: | |||
--restore-to-timestamp string (init incremental restore parameter) if set, run a point in time recovery that restores up to the given timestamp, if possible. Given timestamp in RFC3339 format. Example: '2006-01-02T15:04:05Z07:00' | |||
--restore_concurrency int (init restore parameter) how many concurrent files to restore at once (default 4) | |||
--restore_from_backup (init restore parameter) will check BackupStorage for a recent backup at startup and start there | |||
--restore_from_backup_allowed_engines strings if present will filter out any backups taken with engines not included in the list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New flags should use dashes, not underscores. Sorry, we haven't got around to deprecating and replacing the old-style flags, so we have this pitfall where you follow what looks like the standard pattern, but it isn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For future reference, the vitess-bot checklist is helpful here. It tells you what is expected under New flags
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aha, thanks @deepthi! I will update it
go/flags/endtoend/vttablet.txt
Outdated
@@ -300,6 +300,7 @@ Flags: | |||
--restore-to-timestamp string (init incremental restore parameter) if set, run a point in time recovery that restores up to the given timestamp, if possible. Given timestamp in RFC3339 format. Example: '2006-01-02T15:04:05Z07:00' | |||
--restore_concurrency int (init restore parameter) how many concurrent files to restore at once (default 4) | |||
--restore_from_backup (init restore parameter) will check BackupStorage for a recent backup at startup and start there | |||
--restore_from_backup_allowed_engines strings if present will filter out any backups taken with engines not included in the list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--restore_from_backup_allowed_engines strings if present will filter out any backups taken with engines not included in the list | |
--restore-from-backup-allowed-engines strings (init restore parameter) if set, only backups taken with the specified engines are eligible to be restored |
@@ -299,6 +309,7 @@ func init() { | |||
Root.AddCommand(RemoveBackup) | |||
|
|||
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\".") | |||
RestoreFromBackup.Flags().StringSliceVar(&restoreFromBackupOptions.AllowedBackupEngines, "allowed-backup-engines", restoreFromBackupOptions.AllowedBackupEngines, "if present will filter out any backups taken with engines not included in the list") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RestoreFromBackup.Flags().StringSliceVar(&restoreFromBackupOptions.AllowedBackupEngines, "allowed-backup-engines", restoreFromBackupOptions.AllowedBackupEngines, "if present will filter out any backups taken with engines not included in the list") | |
RestoreFromBackup.Flags().StringSliceVar(&restoreFromBackupOptions.AllowedBackupEngines, "allowed-backup-engines", restoreFromBackupOptions.AllowedBackupEngines, "if set, only backups taken with the specified engines are eligible to be restored") |
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
Signed-off-by: Renan Rangel <rrangel@slack-corp.com>
We'll update all the command reference docs before release. |
err = localCluster.VtctldClientProcess.ExecuteCommand("Backup", "--allow-primary", "--backup-engine=builtin", primary.Alias) | ||
require.NoError(t, err) | ||
engineUsed := getBackupEngineOfLastBackup(t) | ||
require.Equal(t, "builtin", engineUsed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
err = localCluster.VtctldClientProcess.ExecuteCommand("Backup", "--allow-primary", "--backup-engine=xtrabackup", primary.Alias) | ||
require.NoError(t, err) | ||
engineUsed := getBackupEngineOfLastBackup(t) | ||
require.Equal(t, "xtrabackup", engineUsed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
if len(params.AllowedBackupEngines) > 0 && !slices.Contains(params.AllowedBackupEngines, bm.BackupMethod) { | ||
params.Logger.Warningf("Ignoring backup %v because it is using %q backup engine", bh.Name(), bm.BackupMethod) | ||
continue | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
…kup() (vitessio#16428) Signed-off-by: Renan Rangel <rrangel@slack-corp.com> Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Co-authored-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Signed-off-by: 'Renan Rangel' <rrangel@slack-corp.com>
Description
This PR will allow calls to the
vttablet
andvtctld
Backup()
API to specify which backup engine to be used. You might want to specify flags for both and have a default one defined in--backup_engine_implementation
, but then you do not need to restart thevttablet
to be able to switch from one engine to the other.Calls to
Backup()
without the backup engine will just use the default backup engine thevttablet
was started with.It also implements a filter on
RestoreFromBackup()
as to allow certain backup engine to be ignored (e.g. you take backups with both thextrabackupengine
and themysqlshell
engine proposed in #16294) so as to have both physical and logical backups, but you only want to be able to restore from the physical backups unless you specify a particular backup.Related Issue(s)
Fixes #16429
Checklist
Deployment Notes