Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions cmd/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func restoreCmd(passedExecs execs, cmdConfig *cmdConfiguration) (*cobra.Command,
PreRun: func(cmd *cobra.Command, args []string) {
bindFlags(cmd, v)
},
Args: cobra.MinimumNArgs(1),
Args: cobra.RangeArgs(0, 1),
RunE: func(cmd *cobra.Command, args []string) error {
cmdConfig.logger.Debug("starting restore")
ctx := context.Background()
Expand All @@ -40,8 +40,20 @@ func restoreCmd(passedExecs execs, cmdConfig *cmdConfiguration) (*cobra.Command,
}()
ctx = util.ContextWithTracer(ctx, tracer)
_, startupSpan := tracer.Start(ctx, "startup")
targetFile := args[0]
target := v.GetString("target")

// Get target from args[0], --target flag, or DB_RESTORE_TARGET environment variable
var target string
if len(args) > 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change this order? The priority should be CLI flag over command line positional option over env var. I know the positional one is weird, but it has a long history, so I am hesitant to remove it.

target = args[0]
} else {
target = v.GetString("target")
}
if target == "" {
return fmt.Errorf("target must be specified as argument, --target flag, or DB_RESTORE_TARGET environment variable")
}

// Always pass empty targetFile to use the full path from the URL
targetFile := ""
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of just setting targetFile := "" and passing empty strings around, should we completely remove the TargetFile field from the entire codebase?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not exactly work. The "target" really is the store, or location, while the "file" is the path in that location. The fact that you specify it as a single string is a convenience for the restore. Look at how dump works.

Which means that for this to work, you likely will need to separate the single URL into the two parts, file and store.

// get databases namesand mappings
databasesMap := make(map[string]string)
databases := strings.TrimSpace(v.GetString("database"))
Expand Down Expand Up @@ -144,9 +156,6 @@ func restoreCmd(passedExecs execs, cmdConfig *cmdConfiguration) (*cobra.Command,

flags := cmd.Flags()
flags.String("target", "", "full URL target to the backup that you wish to restore")
if err := cmd.MarkFlagRequired("target"); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call here.

return nil, err
}

// compression
flags.String("compression", defaultCompression, "Compression to use. Supported are: `gzip`, `bzip2`, `none`")
Expand Down
12 changes: 10 additions & 2 deletions pkg/storage/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,15 @@ func (s *S3) Pull(ctx context.Context, source, target string, logger *log.Entry)
return 0, fmt.Errorf("failed to get AWS client: %v", err)
}

bucket, path := s.url.Hostname(), path.Join(s.url.Path, source)
bucket := s.url.Hostname()
// If source is empty, use the path from URL directly (for restore command)
// Otherwise, append source to the URL path (for dump command)
var objectPath string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call on cleaning up the overload of path

if source == "" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had some issues a while back with the pathing of objects, that was cleaned up (I could find the PR+commit, if needed). Maybe something still lingers.

It would help if you can explain what combinations trigger the error?

objectPath = strings.TrimPrefix(s.url.Path, "/")
} else {
objectPath = strings.TrimPrefix(path.Join(s.url.Path, source), "/")
}

// Create a downloader with the session and default options
downloader := manager.NewDownloader(client)
Expand All @@ -88,7 +96,7 @@ func (s *S3) Pull(ctx context.Context, source, target string, logger *log.Entry)
// Write the contents of S3 Object to the file
n, err := downloader.Download(context.TODO(), f, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(path),
Key: aws.String(objectPath),
})
if err != nil {
return 0, fmt.Errorf("failed to download file, %v", err)
Expand Down