restic/backend/s3/config.go
Christian Kemper 8f5ff379b7 Introduced a configurable object path prefix for s3 repositories.
Prepends the object path prefix to all s3 paths and allows to have multiple independent
restic backup repositories in a single s3 bucket.

Removed the hardcoded "restic" prefix from s3 paths.

Use "restic" as the default object path prefix for s3 if no other prefix gets specified.
This will retain backward compatibility with existing s3 repository configurations.

Simplified the parse flow to have a single point where we parse the bucket name and the prefix within the bucket.

Added tests for s3 object path prefix and the new default prefix to config_test and location_test.
2016-02-14 06:05:38 -08:00

72 lines
1.7 KiB
Go

package s3
import (
"errors"
"net/url"
"strings"
)
// Config contains all configuration necessary to connect to an s3 compatible
// server.
type Config struct {
Endpoint string
UseHTTP bool
KeyID, Secret string
Bucket string
Prefix string
}
const defaultPrefix = "restic"
// ParseConfig parses the string s and extracts the s3 config. The two
// supported configuration formats are s3://host/bucketname/prefix and
// s3:host:bucketname/prefix. The host can also be a valid s3 region
// name. If no prefix is given the prefix "restic" will be used.
func ParseConfig(s string) (interface{}, error) {
var path []string
cfg := Config{}
if strings.HasPrefix(s, "s3://") {
s = s[5:]
path = strings.SplitN(s, "/", 3)
cfg.Endpoint = path[0]
path = path[1:]
} else if strings.HasPrefix(s, "s3:http") {
s = s[3:]
// assume that a URL has been specified, parse it and
// use the host as the endpoint and the path as the
// bucket name and prefix
url, err := url.Parse(s)
if err != nil {
return nil, err
}
if url.Path == "" {
return nil, errors.New("s3: bucket name not found")
}
cfg.Endpoint = url.Host
if url.Scheme == "http" {
cfg.UseHTTP = true
}
path = strings.SplitN(url.Path[1:], "/", 2)
} else if strings.HasPrefix(s, "s3:") {
s = s[3:]
path = strings.SplitN(s, "/", 3)
cfg.Endpoint = path[0]
path = path[1:]
} else {
return nil, errors.New("s3: invalid format")
}
if len(path) < 1 {
return nil, errors.New("s3: invalid format, host/region or bucket name not found")
}
cfg.Bucket = path[0]
if len(path) > 1 {
cfg.Prefix = path[1]
} else {
cfg.Prefix = defaultPrefix
}
return cfg, nil
}