Fix restore -if-replica-exists with multiple replicas

This commit is contained in:
Toni Spets
2022-08-20 12:56:02 +03:00
committed by Ben Johnson
parent 868d564988
commit 94f0082abd
4 changed files with 30 additions and 7 deletions

View File

@@ -111,8 +111,16 @@ func (c *RestoreCommand) Run(ctx context.Context, args []string) (err error) {
// Build replica from either a URL or config. // Build replica from either a URL or config.
r, err := c.loadReplica(ctx, config, pathOrURL) r, err := c.loadReplica(ctx, config, pathOrURL)
if err != nil { if err == litestream.ErrNoGeneration {
return err // Return an error if no replicas can be loaded to restore from.
// If optional flag set, return success. Useful for automated recovery.
if c.ifReplicaExists {
fmt.Fprintln(c.stdout, "no replicas have generations to restore from, skipping")
return nil
}
return fmt.Errorf("no replicas have generations to restore from")
} else if err != nil {
return fmt.Errorf("cannot determine latest replica: %w", err)
} }
// Determine latest generation if one is not specified. // Determine latest generation if one is not specified.
@@ -218,11 +226,7 @@ func (c *RestoreCommand) loadReplicaFromConfig(ctx context.Context, config Confi
} }
// Determine latest replica to restore from. // Determine latest replica to restore from.
r, err := litestream.LatestReplica(ctx, db.Replicas) return litestream.LatestReplica(ctx, db.Replicas)
if err != nil {
return nil, fmt.Errorf("cannot determine latest replica: %w", err)
}
return r, nil
} }
// Usage prints the help screen to STDOUT. // Usage prints the help screen to STDOUT.

View File

@@ -138,6 +138,19 @@ func TestRestoreCommand(t *testing.T) {
} }
}) })
t.Run("IfReplicaExists/Multiple", func(t *testing.T) {
testDir := filepath.Join("testdata", "restore", "if-replica-exists-flag-multiple")
defer testingutil.Setenv(t, "LITESTREAM_TESTDIR", testDir)()
m, _, stdout, _ := newMain()
err := m.Run(context.Background(), []string{"restore", "-config", filepath.Join(testDir, "litestream.yml"), "-if-replica-exists", filepath.Join(testDir, "db")})
if err != nil {
t.Fatal(err)
} else if got, want := stdout.String(), string(testingutil.ReadFile(t, filepath.Join(testDir, "stdout"))); got != want {
t.Fatalf("stdout=%q, want %q", got, want)
}
})
t.Run("ErrNoBackups", func(t *testing.T) { t.Run("ErrNoBackups", func(t *testing.T) {
testDir := filepath.Join("testdata", "restore", "no-backups") testDir := filepath.Join("testdata", "restore", "no-backups")
defer testingutil.Setenv(t, "LITESTREAM_TESTDIR", testDir)() defer testingutil.Setenv(t, "LITESTREAM_TESTDIR", testDir)()

View File

@@ -0,0 +1,5 @@
dbs:
- path: $LITESTREAM_TESTDIR/db
replicas:
- path: $LITESTREAM_TESTDIR/replica0
- path: $LITESTREAM_TESTDIR/replica1

View File

@@ -0,0 +1 @@
no replicas have generations to restore from, skipping