github.com/fawick/restic@v0.1.1-0.20171126184616-c02923fbfc79/internal/backend/s3/config.go (about)

     1  package s3
     2  
     3  import (
     4  	"net/url"
     5  	"path"
     6  	"strings"
     7  
     8  	"github.com/restic/restic/internal/errors"
     9  	"github.com/restic/restic/internal/options"
    10  )
    11  
    12  // Config contains all configuration necessary to connect to an s3 compatible
    13  // server.
    14  type Config struct {
    15  	Endpoint      string
    16  	UseHTTP       bool
    17  	KeyID, Secret string
    18  	Bucket        string
    19  	Prefix        string
    20  	Layout        string `option:"layout" help:"use this backend layout (default: auto-detect)"`
    21  
    22  	Connections uint `option:"connections" help:"set a limit for the number of concurrent connections (default: 5)"`
    23  	MaxRetries  uint `option:"retries" help:"set the number of retries attempted"`
    24  }
    25  
    26  // NewConfig returns a new Config with the default values filled in.
    27  func NewConfig() Config {
    28  	return Config{
    29  		Connections: 5,
    30  	}
    31  }
    32  
    33  func init() {
    34  	options.Register("s3", Config{})
    35  }
    36  
    37  // ParseConfig parses the string s and extracts the s3 config. The two
    38  // supported configuration formats are s3://host/bucketname/prefix and
    39  // s3:host/bucketname/prefix. The host can also be a valid s3 region
    40  // name. If no prefix is given the prefix "restic" will be used.
    41  func ParseConfig(s string) (interface{}, error) {
    42  	switch {
    43  	case strings.HasPrefix(s, "s3:http"):
    44  		// assume that a URL has been specified, parse it and
    45  		// use the host as the endpoint and the path as the
    46  		// bucket name and prefix
    47  		url, err := url.Parse(s[3:])
    48  		if err != nil {
    49  			return nil, errors.Wrap(err, "url.Parse")
    50  		}
    51  
    52  		if url.Path == "" {
    53  			return nil, errors.New("s3: bucket name not found")
    54  		}
    55  
    56  		path := strings.SplitN(url.Path[1:], "/", 2)
    57  		return createConfig(url.Host, path, url.Scheme == "http")
    58  	case strings.HasPrefix(s, "s3://"):
    59  		s = s[5:]
    60  	case strings.HasPrefix(s, "s3:"):
    61  		s = s[3:]
    62  	default:
    63  		return nil, errors.New("s3: invalid format")
    64  	}
    65  	// use the first entry of the path as the endpoint and the
    66  	// remainder as bucket name and prefix
    67  	path := strings.SplitN(s, "/", 3)
    68  	return createConfig(path[0], path[1:], false)
    69  }
    70  
    71  func createConfig(endpoint string, p []string, useHTTP bool) (interface{}, error) {
    72  	if len(p) < 1 {
    73  		return nil, errors.New("s3: invalid format, host/region or bucket name not found")
    74  	}
    75  
    76  	var prefix string
    77  	if len(p) > 1 && p[1] != "" {
    78  		prefix = path.Clean(p[1])
    79  	}
    80  
    81  	cfg := NewConfig()
    82  	cfg.Endpoint = endpoint
    83  	cfg.UseHTTP = useHTTP
    84  	cfg.Bucket = p[0]
    85  	cfg.Prefix = prefix
    86  	return cfg, nil
    87  }