mirror of
https://github.com/octoleo/restic.git
synced 2024-11-26 14:56:29 +00:00
Merge pull request #1276 from fawick/supply_ca_cert
Add REST backend option to use CA root certificate
This commit is contained in:
commit
c5553ec855
@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/backend"
|
||||||
"github.com/restic/restic/internal/backend/azure"
|
"github.com/restic/restic/internal/backend/azure"
|
||||||
"github.com/restic/restic/internal/backend/b2"
|
"github.com/restic/restic/internal/backend/b2"
|
||||||
"github.com/restic/restic/internal/backend/gs"
|
"github.com/restic/restic/internal/backend/gs"
|
||||||
@ -41,6 +42,7 @@ type GlobalOptions struct {
|
|||||||
JSON bool
|
JSON bool
|
||||||
CacheDir string
|
CacheDir string
|
||||||
NoCache bool
|
NoCache bool
|
||||||
|
CACerts []string
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
password string
|
password string
|
||||||
@ -73,6 +75,7 @@ func init() {
|
|||||||
f.BoolVarP(&globalOptions.JSON, "json", "", false, "set output mode to JSON for commands that support it")
|
f.BoolVarP(&globalOptions.JSON, "json", "", false, "set output mode to JSON for commands that support it")
|
||||||
f.StringVar(&globalOptions.CacheDir, "cache-dir", "", "set the cache directory")
|
f.StringVar(&globalOptions.CacheDir, "cache-dir", "", "set the cache directory")
|
||||||
f.BoolVar(&globalOptions.NoCache, "no-cache", false, "do not use a local cache")
|
f.BoolVar(&globalOptions.NoCache, "no-cache", false, "do not use a local cache")
|
||||||
|
f.StringSliceVar(&globalOptions.CACerts, "cacert", nil, "path to load root certificates from (default: use system certificates)")
|
||||||
f.StringSliceVarP(&globalOptions.Options, "option", "o", []string{}, "set extended option (`key=value`, can be specified multiple times)")
|
f.StringSliceVarP(&globalOptions.Options, "option", "o", []string{}, "set extended option (`key=value`, can be specified multiple times)")
|
||||||
|
|
||||||
restoreTerminal()
|
restoreTerminal()
|
||||||
@ -485,23 +488,28 @@ func open(s string, opts options.Options) (restic.Backend, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rt, err := backend.Transport(globalOptions.CACerts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
switch loc.Scheme {
|
switch loc.Scheme {
|
||||||
case "local":
|
case "local":
|
||||||
be, err = local.Open(cfg.(local.Config))
|
be, err = local.Open(cfg.(local.Config))
|
||||||
case "sftp":
|
case "sftp":
|
||||||
be, err = sftp.Open(cfg.(sftp.Config), SuspendSignalHandler, InstallSignalHandler)
|
be, err = sftp.Open(cfg.(sftp.Config), SuspendSignalHandler, InstallSignalHandler)
|
||||||
case "s3":
|
case "s3":
|
||||||
be, err = s3.Open(cfg.(s3.Config))
|
be, err = s3.Open(cfg.(s3.Config), rt)
|
||||||
case "gs":
|
case "gs":
|
||||||
be, err = gs.Open(cfg.(gs.Config))
|
be, err = gs.Open(cfg.(gs.Config))
|
||||||
case "azure":
|
case "azure":
|
||||||
be, err = azure.Open(cfg.(azure.Config))
|
be, err = azure.Open(cfg.(azure.Config), rt)
|
||||||
case "swift":
|
case "swift":
|
||||||
be, err = swift.Open(cfg.(swift.Config))
|
be, err = swift.Open(cfg.(swift.Config), rt)
|
||||||
case "b2":
|
case "b2":
|
||||||
be, err = b2.Open(cfg.(b2.Config))
|
be, err = b2.Open(cfg.(b2.Config), rt)
|
||||||
case "rest":
|
case "rest":
|
||||||
be, err = rest.Open(cfg.(rest.Config))
|
be, err = rest.Open(cfg.(rest.Config), rt)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, errors.Fatalf("invalid backend: %q", loc.Scheme)
|
return nil, errors.Fatalf("invalid backend: %q", loc.Scheme)
|
||||||
@ -537,23 +545,28 @@ func create(s string, opts options.Options) (restic.Backend, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rt, err := backend.Transport(globalOptions.CACerts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
switch loc.Scheme {
|
switch loc.Scheme {
|
||||||
case "local":
|
case "local":
|
||||||
return local.Create(cfg.(local.Config))
|
return local.Create(cfg.(local.Config))
|
||||||
case "sftp":
|
case "sftp":
|
||||||
return sftp.Create(cfg.(sftp.Config), SuspendSignalHandler, InstallSignalHandler)
|
return sftp.Create(cfg.(sftp.Config), SuspendSignalHandler, InstallSignalHandler)
|
||||||
case "s3":
|
case "s3":
|
||||||
return s3.Create(cfg.(s3.Config))
|
return s3.Create(cfg.(s3.Config), rt)
|
||||||
case "gs":
|
case "gs":
|
||||||
return gs.Create(cfg.(gs.Config))
|
return gs.Create(cfg.(gs.Config))
|
||||||
case "azure":
|
case "azure":
|
||||||
return azure.Create(cfg.(azure.Config))
|
return azure.Create(cfg.(azure.Config), rt)
|
||||||
case "swift":
|
case "swift":
|
||||||
return swift.Open(cfg.(swift.Config))
|
return swift.Open(cfg.(swift.Config), rt)
|
||||||
case "b2":
|
case "b2":
|
||||||
return b2.Create(cfg.(b2.Config))
|
return b2.Create(cfg.(b2.Config), rt)
|
||||||
case "rest":
|
case "rest":
|
||||||
return rest.Create(cfg.(rest.Config))
|
return rest.Create(cfg.(rest.Config), rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Log("invalid repository scheme: %v", s)
|
debug.Log("invalid repository scheme: %v", s)
|
||||||
|
@ -30,7 +30,7 @@ const defaultListMaxItems = 5000
|
|||||||
// make sure that *Backend implements backend.Backend
|
// make sure that *Backend implements backend.Backend
|
||||||
var _ restic.Backend = &Backend{}
|
var _ restic.Backend = &Backend{}
|
||||||
|
|
||||||
func open(cfg Config) (*Backend, error) {
|
func open(cfg Config, rt http.RoundTripper) (*Backend, error) {
|
||||||
debug.Log("open, config %#v", cfg)
|
debug.Log("open, config %#v", cfg)
|
||||||
|
|
||||||
client, err := storage.NewBasicClient(cfg.AccountName, cfg.AccountKey)
|
client, err := storage.NewBasicClient(cfg.AccountName, cfg.AccountKey)
|
||||||
@ -38,7 +38,7 @@ func open(cfg Config) (*Backend, error) {
|
|||||||
return nil, errors.Wrap(err, "NewBasicClient")
|
return nil, errors.Wrap(err, "NewBasicClient")
|
||||||
}
|
}
|
||||||
|
|
||||||
client.HTTPClient = &http.Client{Transport: backend.Transport()}
|
client.HTTPClient = &http.Client{Transport: rt}
|
||||||
|
|
||||||
service := client.GetBlobService()
|
service := client.GetBlobService()
|
||||||
|
|
||||||
@ -63,14 +63,14 @@ func open(cfg Config) (*Backend, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open opens the Azure backend at specified container.
|
// Open opens the Azure backend at specified container.
|
||||||
func Open(cfg Config) (restic.Backend, error) {
|
func Open(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
return open(cfg)
|
return open(cfg, rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create opens the Azure backend at specified container and creates the container if
|
// Create opens the Azure backend at specified container and creates the container if
|
||||||
// it does not exist yet.
|
// it does not exist yet.
|
||||||
func Create(cfg Config) (restic.Backend, error) {
|
func Create(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
be, err := open(cfg)
|
be, err := open(cfg, rt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "open")
|
return nil, errors.Wrap(err, "open")
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/backend"
|
||||||
"github.com/restic/restic/internal/backend/azure"
|
"github.com/restic/restic/internal/backend/azure"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/errors"
|
"github.com/restic/restic/internal/errors"
|
||||||
@ -15,6 +16,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func newAzureTestSuite(t testing.TB) *test.Suite {
|
func newAzureTestSuite(t testing.TB) *test.Suite {
|
||||||
|
tr, err := backend.Transport(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &test.Suite{
|
return &test.Suite{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
@ -37,7 +43,7 @@ func newAzureTestSuite(t testing.TB) *test.Suite {
|
|||||||
Create: func(config interface{}) (restic.Backend, error) {
|
Create: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(azure.Config)
|
cfg := config.(azure.Config)
|
||||||
|
|
||||||
be, err := azure.Create(cfg)
|
be, err := azure.Create(cfg, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -57,14 +63,15 @@ func newAzureTestSuite(t testing.TB) *test.Suite {
|
|||||||
// OpenFn is a function that opens a previously created temporary repository.
|
// OpenFn is a function that opens a previously created temporary repository.
|
||||||
Open: func(config interface{}) (restic.Backend, error) {
|
Open: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(azure.Config)
|
cfg := config.(azure.Config)
|
||||||
return azure.Open(cfg)
|
|
||||||
|
return azure.Open(cfg, tr)
|
||||||
},
|
},
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
// CleanupFn removes data created during the tests.
|
||||||
Cleanup: func(config interface{}) error {
|
Cleanup: func(config interface{}) error {
|
||||||
cfg := config.(azure.Config)
|
cfg := config.(azure.Config)
|
||||||
|
|
||||||
be, err := azure.Open(cfg)
|
be, err := azure.Open(cfg, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package b2
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -29,8 +30,8 @@ const defaultListMaxItems = 1000
|
|||||||
// ensure statically that *b2Backend implements restic.Backend.
|
// ensure statically that *b2Backend implements restic.Backend.
|
||||||
var _ restic.Backend = &b2Backend{}
|
var _ restic.Backend = &b2Backend{}
|
||||||
|
|
||||||
func newClient(ctx context.Context, cfg Config) (*b2.Client, error) {
|
func newClient(ctx context.Context, cfg Config, rt http.RoundTripper) (*b2.Client, error) {
|
||||||
opts := []b2.ClientOption{b2.Transport(backend.Transport())}
|
opts := []b2.ClientOption{b2.Transport(rt)}
|
||||||
|
|
||||||
c, err := b2.NewClient(ctx, cfg.AccountID, cfg.Key, opts...)
|
c, err := b2.NewClient(ctx, cfg.AccountID, cfg.Key, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,13 +41,13 @@ func newClient(ctx context.Context, cfg Config) (*b2.Client, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open opens a connection to the B2 service.
|
// Open opens a connection to the B2 service.
|
||||||
func Open(cfg Config) (restic.Backend, error) {
|
func Open(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
debug.Log("cfg %#v", cfg)
|
debug.Log("cfg %#v", cfg)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.TODO())
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
client, err := newClient(ctx, cfg)
|
client, err := newClient(ctx, cfg, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -77,13 +78,13 @@ func Open(cfg Config) (restic.Backend, error) {
|
|||||||
|
|
||||||
// Create opens a connection to the B2 service. If the bucket does not exist yet,
|
// Create opens a connection to the B2 service. If the bucket does not exist yet,
|
||||||
// it is created.
|
// it is created.
|
||||||
func Create(cfg Config) (restic.Backend, error) {
|
func Create(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
debug.Log("cfg %#v", cfg)
|
debug.Log("cfg %#v", cfg)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.TODO())
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
client, err := newClient(ctx, cfg)
|
client, err := newClient(ctx, cfg, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/backend"
|
||||||
"github.com/restic/restic/internal/backend/b2"
|
"github.com/restic/restic/internal/backend/b2"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
@ -15,6 +16,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func newB2TestSuite(t testing.TB) *test.Suite {
|
func newB2TestSuite(t testing.TB) *test.Suite {
|
||||||
|
tr, err := backend.Transport(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &test.Suite{
|
return &test.Suite{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
@ -39,19 +45,19 @@ func newB2TestSuite(t testing.TB) *test.Suite {
|
|||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
// CreateFn is a function that creates a temporary repository for the tests.
|
||||||
Create: func(config interface{}) (restic.Backend, error) {
|
Create: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(b2.Config)
|
cfg := config.(b2.Config)
|
||||||
return b2.Create(cfg)
|
return b2.Create(cfg, tr)
|
||||||
},
|
},
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
// OpenFn is a function that opens a previously created temporary repository.
|
||||||
Open: func(config interface{}) (restic.Backend, error) {
|
Open: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(b2.Config)
|
cfg := config.(b2.Config)
|
||||||
return b2.Open(cfg)
|
return b2.Open(cfg, tr)
|
||||||
},
|
},
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
// CleanupFn removes data created during the tests.
|
||||||
Cleanup: func(config interface{}) error {
|
Cleanup: func(config interface{}) error {
|
||||||
cfg := config.(b2.Config)
|
cfg := config.(b2.Config)
|
||||||
be, err := b2.Open(cfg)
|
be, err := b2.Open(cfg, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package backend
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
@ -8,8 +12,10 @@ import (
|
|||||||
"github.com/restic/restic/internal/debug"
|
"github.com/restic/restic/internal/debug"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Transport returns a new http.RoundTripper with default settings applied.
|
// Transport returns a new http.RoundTripper with default settings applied. If
|
||||||
func Transport() http.RoundTripper {
|
// a custom rootCertFilename is non-empty, it must point to a valid PEM file,
|
||||||
|
// otherwise the function will return an error.
|
||||||
|
func Transport(rootCertFilenames []string) (http.RoundTripper, error) {
|
||||||
// copied from net/http
|
// copied from net/http
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
@ -25,6 +31,28 @@ func Transport() http.RoundTripper {
|
|||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rootCertFilenames == nil {
|
||||||
|
return debug.RoundTripper(tr), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := x509.NewCertPool()
|
||||||
|
for _, filename := range rootCertFilenames {
|
||||||
|
if filename == "" {
|
||||||
|
return nil, fmt.Errorf("empty filename for root certificate supplied")
|
||||||
|
}
|
||||||
|
b, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read root certificate: %v", err)
|
||||||
|
}
|
||||||
|
if ok := p.AppendCertsFromPEM(b); !ok {
|
||||||
|
return nil, fmt.Errorf("cannot parse root certificate from %q", filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.TLSClientConfig = &tls.Config{
|
||||||
|
RootCAs: p,
|
||||||
|
}
|
||||||
|
|
||||||
// wrap in the debug round tripper
|
// wrap in the debug round tripper
|
||||||
return debug.RoundTripper(tr)
|
return debug.RoundTripper(tr), nil
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,8 @@ type restBackend struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open opens the REST backend with the given config.
|
// Open opens the REST backend with the given config.
|
||||||
func Open(cfg Config) (restic.Backend, error) {
|
func Open(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
client := &http.Client{Transport: backend.Transport()}
|
client := &http.Client{Transport: rt}
|
||||||
|
|
||||||
sem, err := backend.NewSemaphore(cfg.Connections)
|
sem, err := backend.NewSemaphore(cfg.Connections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -56,8 +56,8 @@ func Open(cfg Config) (restic.Backend, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new REST on server configured in config.
|
// Create creates a new REST on server configured in config.
|
||||||
func Create(cfg Config) (restic.Backend, error) {
|
func Create(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
be, err := Open(cfg)
|
be, err := Open(cfg, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/backend"
|
||||||
"github.com/restic/restic/internal/backend/rest"
|
"github.com/restic/restic/internal/backend/rest"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
@ -61,6 +62,11 @@ func runRESTServer(ctx context.Context, t testing.TB, dir string) func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
func newTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
||||||
|
tr, err := backend.Transport(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &test.Suite{
|
return &test.Suite{
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
NewConfig: func() (interface{}, error) {
|
NewConfig: func() (interface{}, error) {
|
||||||
@ -84,13 +90,13 @@ func newTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
|||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
// CreateFn is a function that creates a temporary repository for the tests.
|
||||||
Create: func(config interface{}) (restic.Backend, error) {
|
Create: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(rest.Config)
|
cfg := config.(rest.Config)
|
||||||
return rest.Create(cfg)
|
return rest.Create(cfg, tr)
|
||||||
},
|
},
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
// OpenFn is a function that opens a previously created temporary repository.
|
||||||
Open: func(config interface{}) (restic.Backend, error) {
|
Open: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(rest.Config)
|
cfg := config.(rest.Config)
|
||||||
return rest.Open(cfg)
|
return rest.Open(cfg, tr)
|
||||||
},
|
},
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
// CleanupFn removes data created during the tests.
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@ -32,7 +33,7 @@ var _ restic.Backend = &Backend{}
|
|||||||
|
|
||||||
const defaultLayout = "default"
|
const defaultLayout = "default"
|
||||||
|
|
||||||
func open(cfg Config) (*Backend, error) {
|
func open(cfg Config, rt http.RoundTripper) (*Backend, error) {
|
||||||
debug.Log("open, config %#v", cfg)
|
debug.Log("open, config %#v", cfg)
|
||||||
|
|
||||||
if cfg.MaxRetries > 0 {
|
if cfg.MaxRetries > 0 {
|
||||||
@ -70,7 +71,7 @@ func open(cfg Config) (*Backend, error) {
|
|||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
client.SetCustomTransport(backend.Transport())
|
client.SetCustomTransport(rt)
|
||||||
|
|
||||||
l, err := backend.ParseLayout(be, cfg.Layout, defaultLayout, cfg.Prefix)
|
l, err := backend.ParseLayout(be, cfg.Layout, defaultLayout, cfg.Prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -84,14 +85,14 @@ func open(cfg Config) (*Backend, error) {
|
|||||||
|
|
||||||
// Open opens the S3 backend at bucket and region. The bucket is created if it
|
// Open opens the S3 backend at bucket and region. The bucket is created if it
|
||||||
// does not exist yet.
|
// does not exist yet.
|
||||||
func Open(cfg Config) (restic.Backend, error) {
|
func Open(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
return open(cfg)
|
return open(cfg, rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create opens the S3 backend at bucket and region and creates the bucket if
|
// Create opens the S3 backend at bucket and region and creates the bucket if
|
||||||
// it does not exist yet.
|
// it does not exist yet.
|
||||||
func Create(cfg Config) (restic.Backend, error) {
|
func Create(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
be, err := open(cfg)
|
be, err := open(cfg, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "open")
|
return nil, errors.Wrap(err, "open")
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/backend"
|
||||||
"github.com/restic/restic/internal/backend/s3"
|
"github.com/restic/restic/internal/backend/s3"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
@ -103,9 +105,9 @@ type MinioTestConfig struct {
|
|||||||
stopServer func()
|
stopServer func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createS3(t testing.TB, cfg MinioTestConfig) (be restic.Backend, err error) {
|
func createS3(t testing.TB, cfg MinioTestConfig, tr http.RoundTripper) (be restic.Backend, err error) {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
be, err = s3.Create(cfg.Config)
|
be, err = s3.Create(cfg.Config, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("s3 open: try %d: error %v", i, err)
|
t.Logf("s3 open: try %d: error %v", i, err)
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
@ -119,6 +121,11 @@ func createS3(t testing.TB, cfg MinioTestConfig) (be restic.Backend, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
||||||
|
tr, err := backend.Transport(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &test.Suite{
|
return &test.Suite{
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
NewConfig: func() (interface{}, error) {
|
NewConfig: func() (interface{}, error) {
|
||||||
@ -142,7 +149,7 @@ func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
|||||||
Create: func(config interface{}) (restic.Backend, error) {
|
Create: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(MinioTestConfig)
|
cfg := config.(MinioTestConfig)
|
||||||
|
|
||||||
be, err := createS3(t, cfg)
|
be, err := createS3(t, cfg, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -162,7 +169,7 @@ func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite {
|
|||||||
// OpenFn is a function that opens a previously created temporary repository.
|
// OpenFn is a function that opens a previously created temporary repository.
|
||||||
Open: func(config interface{}) (restic.Backend, error) {
|
Open: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(MinioTestConfig)
|
cfg := config.(MinioTestConfig)
|
||||||
return s3.Open(cfg.Config)
|
return s3.Open(cfg.Config, tr)
|
||||||
},
|
},
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
// CleanupFn removes data created during the tests.
|
||||||
@ -214,6 +221,11 @@ func BenchmarkBackendMinio(t *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newS3TestSuite(t testing.TB) *test.Suite {
|
func newS3TestSuite(t testing.TB) *test.Suite {
|
||||||
|
tr, err := backend.Transport(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &test.Suite{
|
return &test.Suite{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
@ -236,7 +248,7 @@ func newS3TestSuite(t testing.TB) *test.Suite {
|
|||||||
Create: func(config interface{}) (restic.Backend, error) {
|
Create: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(s3.Config)
|
cfg := config.(s3.Config)
|
||||||
|
|
||||||
be, err := s3.Create(cfg)
|
be, err := s3.Create(cfg, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -256,14 +268,14 @@ func newS3TestSuite(t testing.TB) *test.Suite {
|
|||||||
// OpenFn is a function that opens a previously created temporary repository.
|
// OpenFn is a function that opens a previously created temporary repository.
|
||||||
Open: func(config interface{}) (restic.Backend, error) {
|
Open: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(s3.Config)
|
cfg := config.(s3.Config)
|
||||||
return s3.Open(cfg)
|
return s3.Open(cfg, tr)
|
||||||
},
|
},
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
// CleanupFn removes data created during the tests.
|
||||||
Cleanup: func(config interface{}) error {
|
Cleanup: func(config interface{}) error {
|
||||||
cfg := config.(s3.Config)
|
cfg := config.(s3.Config)
|
||||||
|
|
||||||
be, err := s3.Open(cfg)
|
be, err := s3.Open(cfg, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ var _ restic.Backend = &beSwift{}
|
|||||||
|
|
||||||
// Open opens the swift backend at a container in region. The container is
|
// Open opens the swift backend at a container in region. The container is
|
||||||
// created if it does not exist yet.
|
// created if it does not exist yet.
|
||||||
func Open(cfg Config) (restic.Backend, error) {
|
func Open(cfg Config, rt http.RoundTripper) (restic.Backend, error) {
|
||||||
debug.Log("config %#v", cfg)
|
debug.Log("config %#v", cfg)
|
||||||
|
|
||||||
sem, err := backend.NewSemaphore(cfg.Connections)
|
sem, err := backend.NewSemaphore(cfg.Connections)
|
||||||
@ -58,7 +58,7 @@ func Open(cfg Config) (restic.Backend, error) {
|
|||||||
ConnectTimeout: time.Minute,
|
ConnectTimeout: time.Minute,
|
||||||
Timeout: time.Minute,
|
Timeout: time.Minute,
|
||||||
|
|
||||||
Transport: backend.Transport(),
|
Transport: rt,
|
||||||
},
|
},
|
||||||
sem: sem,
|
sem: sem,
|
||||||
container: cfg.Container,
|
container: cfg.Container,
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/backend"
|
||||||
"github.com/restic/restic/internal/backend/swift"
|
"github.com/restic/restic/internal/backend/swift"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/errors"
|
"github.com/restic/restic/internal/errors"
|
||||||
@ -15,6 +16,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func newSwiftTestSuite(t testing.TB) *test.Suite {
|
func newSwiftTestSuite(t testing.TB) *test.Suite {
|
||||||
|
tr, err := backend.Transport(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &test.Suite{
|
return &test.Suite{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
@ -55,7 +61,7 @@ func newSwiftTestSuite(t testing.TB) *test.Suite {
|
|||||||
Create: func(config interface{}) (restic.Backend, error) {
|
Create: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(swift.Config)
|
cfg := config.(swift.Config)
|
||||||
|
|
||||||
be, err := swift.Open(cfg)
|
be, err := swift.Open(cfg, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -75,14 +81,14 @@ func newSwiftTestSuite(t testing.TB) *test.Suite {
|
|||||||
// OpenFn is a function that opens a previously created temporary repository.
|
// OpenFn is a function that opens a previously created temporary repository.
|
||||||
Open: func(config interface{}) (restic.Backend, error) {
|
Open: func(config interface{}) (restic.Backend, error) {
|
||||||
cfg := config.(swift.Config)
|
cfg := config.(swift.Config)
|
||||||
return swift.Open(cfg)
|
return swift.Open(cfg, tr)
|
||||||
},
|
},
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
// CleanupFn removes data created during the tests.
|
||||||
Cleanup: func(config interface{}) error {
|
Cleanup: func(config interface{}) error {
|
||||||
cfg := config.(swift.Config)
|
cfg := config.(swift.Config)
|
||||||
|
|
||||||
be, err := swift.Open(cfg)
|
be, err := swift.Open(cfg, tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user