Allow overriding the default username/hostname in kopia (#3223)

This allows setting the username/hostname
kopia will use for maintenance. This
information is recorded in the kopia config
file during connect and reused during open

If no values are given, kopia pulls the
values from the OS

---

#### Does this PR need a docs update or release note?

- [ ]  Yes, it's included
- [ ] 🕐 Yes, but in a later PR
- [x]  No

#### Type of change

- [x] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Supportability/Tests
- [ ] 💻 CI/Deployment
- [ ] 🧹 Tech Debt/Cleanup

#### Issue(s)

* #3077

#### Test Plan

- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2023-04-27 15:47:35 -07:00 committed by GitHub
parent 754e14d7a6
commit 6ac8c9f331
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 103 additions and 29 deletions

View File

@ -18,6 +18,7 @@ import (
"github.com/kopia/kopia/snapshot/snapshotfs"
"github.com/pkg/errors"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/storage"
)
@ -69,7 +70,7 @@ func NewConn(s storage.Storage) *conn {
}
}
func (w *conn) Initialize(ctx context.Context) error {
func (w *conn) Initialize(ctx context.Context, opts control.RepoOptions) error {
bst, err := blobStoreByProvider(ctx, w.storage)
if err != nil {
return clues.Wrap(err, "initializing storage")
@ -92,6 +93,7 @@ func (w *conn) Initialize(ctx context.Context) error {
err = w.commonConnect(
ctx,
opts,
cfg.KopiaCfgDir,
bst,
cfg.CorsoPassphrase,
@ -108,7 +110,7 @@ func (w *conn) Initialize(ctx context.Context) error {
return nil
}
func (w *conn) Connect(ctx context.Context) error {
func (w *conn) Connect(ctx context.Context, opts control.RepoOptions) error {
bst, err := blobStoreByProvider(ctx, w.storage)
if err != nil {
return clues.Wrap(err, "initializing storage")
@ -122,6 +124,7 @@ func (w *conn) Connect(ctx context.Context) error {
return w.commonConnect(
ctx,
opts,
cfg.KopiaCfgDir,
bst,
cfg.CorsoPassphrase,
@ -131,16 +134,21 @@ func (w *conn) Connect(ctx context.Context) error {
func (w *conn) commonConnect(
ctx context.Context,
opts control.RepoOptions,
configDir string,
bst blob.Storage,
password, compressor string,
) error {
var opts *repo.ConnectOptions
kopiaOpts := &repo.ConnectOptions{
ClientOptions: repo.ClientOptions{
Username: opts.User,
Hostname: opts.Host,
},
}
if len(configDir) > 0 {
opts = &repo.ConnectOptions{
CachingOptions: content.CachingOptions{
CacheDirectory: configDir,
},
kopiaOpts.CachingOptions = content.CachingOptions{
CacheDirectory: configDir,
}
} else {
configDir = defaultKopiaConfigDir
@ -154,7 +162,7 @@ func (w *conn) commonConnect(
cfgFile,
bst,
password,
opts,
kopiaOpts,
); err != nil {
return clues.Wrap(err, "connecting to repo").WithClues(ctx)
}

View File

@ -14,16 +14,18 @@ import (
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/storage"
)
//revive:disable:context-as-argument
func openKopiaRepo(t *testing.T, ctx context.Context) (*conn, error) {
//revive:enable:context-as-argument
func openKopiaRepo(
t *testing.T,
ctx context.Context, //revive:disable-line:context-as-argument
) (*conn, error) {
st := tester.NewPrefixedS3Storage(t)
k := NewConn(st)
if err := k.Initialize(ctx); err != nil {
if err := k.Initialize(ctx, control.RepoOptions{}); err != nil {
return nil, err
}
@ -77,13 +79,13 @@ func (suite *WrapperIntegrationSuite) TestRepoExistsError() {
st := tester.NewPrefixedS3Storage(t)
k := NewConn(st)
err := k.Initialize(ctx)
err := k.Initialize(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
err = k.Close(ctx)
require.NoError(t, err, clues.ToCore(err))
err = k.Initialize(ctx)
err = k.Initialize(ctx, control.RepoOptions{})
assert.Error(t, err, clues.ToCore(err))
assert.ErrorIs(t, err, ErrorRepoAlreadyExists)
}
@ -97,7 +99,7 @@ func (suite *WrapperIntegrationSuite) TestBadProviderErrors() {
st.Provider = storage.ProviderUnknown
k := NewConn(st)
err := k.Initialize(ctx)
err := k.Initialize(ctx, control.RepoOptions{})
assert.Error(t, err, clues.ToCore(err))
}
@ -109,7 +111,7 @@ func (suite *WrapperIntegrationSuite) TestConnectWithoutInitErrors() {
st := tester.NewPrefixedS3Storage(t)
k := NewConn(st)
err := k.Connect(ctx)
err := k.Connect(ctx, control.RepoOptions{})
assert.Error(t, err, clues.ToCore(err))
}
@ -356,7 +358,7 @@ func (suite *WrapperIntegrationSuite) TestConfigDefaultsSetOnInitAndNotOnConnect
err = k.Close(ctx)
require.NoError(t, err, clues.ToCore(err))
err = k.Connect(ctx)
err = k.Connect(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
defer func() {
@ -384,9 +386,63 @@ func (suite *WrapperIntegrationSuite) TestInitAndConnWithTempDirectory() {
require.NoError(t, err, clues.ToCore(err))
// Re-open with Connect.
err = k.Connect(ctx)
err = k.Connect(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
err = k.Close(ctx)
assert.NoError(t, err, clues.ToCore(err))
}
func (suite *WrapperIntegrationSuite) TestSetUserAndHost() {
ctx, flush := tester.NewContext()
defer flush()
opts := control.RepoOptions{
User: "foo",
Host: "bar",
}
t := suite.T()
st := tester.NewPrefixedS3Storage(t)
k := NewConn(st)
err := k.Initialize(ctx, opts)
require.NoError(t, err, clues.ToCore(err))
kopiaOpts := k.ClientOptions()
require.Equal(t, opts.User, kopiaOpts.Username)
require.Equal(t, opts.Host, kopiaOpts.Hostname)
err = k.Close(ctx)
require.NoError(t, err, clues.ToCore(err))
// Re-open with Connect and a different user/hostname.
opts.User = "hello"
opts.Host = "world"
err = k.Connect(ctx, opts)
require.NoError(t, err, clues.ToCore(err))
kopiaOpts = k.ClientOptions()
require.Equal(t, opts.User, kopiaOpts.Username)
require.Equal(t, opts.Host, kopiaOpts.Hostname)
err = k.Close(ctx)
require.NoError(t, err, clues.ToCore(err))
// Make sure not setting the values uses the kopia defaults.
opts.User = ""
opts.Host = ""
err = k.Connect(ctx, opts)
require.NoError(t, err, clues.ToCore(err))
kopiaOpts = k.ClientOptions()
assert.NotEmpty(t, kopiaOpts.Username)
assert.NotEqual(t, "hello", kopiaOpts.Username)
assert.NotEmpty(t, kopiaOpts.Hostname)
assert.NotEqual(t, "world", kopiaOpts.Hostname)
err = k.Close(ctx)
assert.NoError(t, err, clues.ToCore(err))
}

View File

@ -17,6 +17,7 @@ import (
"github.com/alcionai/corso/src/internal/model"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/backup"
"github.com/alcionai/corso/src/pkg/control"
)
type fooModel struct {
@ -803,7 +804,7 @@ func openConnAndModelStore(
st := tester.NewPrefixedS3Storage(t)
c := NewConn(st)
err := c.Initialize(ctx)
err := c.Initialize(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
defer func() {
@ -822,7 +823,7 @@ func reconnectToModelStore(
ctx context.Context, //revive:disable-line:context-as-argument
c *conn,
) *ModelStore {
err := c.Connect(ctx)
err := c.Connect(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
defer func() {

View File

@ -83,7 +83,7 @@ func prepNewTestBackupOp(
k = kopia.NewConn(st)
)
err := k.Initialize(ctx)
err := k.Initialize(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
// kopiaRef comes with a count of 1 and Wrapper bumps it again so safe

View File

@ -175,7 +175,7 @@ func (suite *RestoreOpIntegrationSuite) SetupSuite() {
suite.acct = tester.NewM365Account(t)
err := k.Initialize(ctx)
err := k.Initialize(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
suite.kopiaCloser = func(ctx context.Context) {

View File

@ -12,6 +12,7 @@ import (
"github.com/alcionai/corso/src/internal/kopia"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path"
)
@ -41,7 +42,7 @@ func (suite *StreamStoreIntgSuite) SetupSubTest() {
st := tester.NewPrefixedS3Storage(t)
k := kopia.NewConn(st)
require.NoError(t, k.Initialize(ctx))
require.NoError(t, k.Initialize(ctx, control.RepoOptions{}))
suite.kcloser = func() { k.Close(ctx) }

View File

@ -13,6 +13,7 @@ type Options struct {
SkipReduce bool `json:"skipReduce"`
ToggleFeatures Toggles `json:"toggleFeatures"`
Parallelism Parallelism `json:"parallelism"`
Repo RepoOptions `json:"repo"`
}
type FailureBehavior string
@ -33,6 +34,12 @@ const (
BestEffort FailureBehavior = "best-effort"
)
// Repo represents options that are specific to the repo storing backed up data.
type RepoOptions struct {
User string `json:"user"`
Host string `json:"host"`
}
// Defaults provides an Options with the default values set.
func Defaults() Options {
return Options{

View File

@ -120,7 +120,7 @@ func Initialize(
}()
kopiaRef := kopia.NewConn(s)
if err := kopiaRef.Initialize(ctx); err != nil {
if err := kopiaRef.Initialize(ctx, opts.Repo); err != nil {
// replace common internal errors so that sdk users can check results with errors.Is()
if errors.Is(err, kopia.ErrorRepoAlreadyExists) {
return nil, clues.Stack(ErrorRepoAlreadyExists, err).WithClues(ctx)
@ -202,7 +202,7 @@ func Connect(
defer close(complete)
kopiaRef := kopia.NewConn(s)
if err := kopiaRef.Connect(ctx); err != nil {
if err := kopiaRef.Connect(ctx, opts.Repo); err != nil {
return nil, clues.Wrap(err, "connecting kopia client")
}
// kopiaRef comes with a count of 1 and NewWrapper/NewModelStore bumps it again so safe

View File

@ -20,6 +20,7 @@ import (
"github.com/alcionai/corso/src/internal/version"
"github.com/alcionai/corso/src/pkg/backup"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
@ -236,10 +237,10 @@ func (suite *RepositoryModelIntgSuite) SetupSuite() {
require.NotNil(t, k)
err = k.Initialize(ctx)
err = k.Initialize(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
err = k.Connect(ctx)
err = k.Connect(ctx, control.RepoOptions{})
require.NoError(t, err, clues.ToCore(err))
suite.kopiaCloser = func(ctx context.Context) {
@ -286,8 +287,8 @@ func (suite *RepositoryModelIntgSuite) TestGetRepositoryModel() {
k = kopia.NewConn(s)
)
require.NoError(t, k.Initialize(ctx))
require.NoError(t, k.Connect(ctx))
require.NoError(t, k.Initialize(ctx, control.RepoOptions{}))
require.NoError(t, k.Connect(ctx, control.RepoOptions{}))
defer k.Close(ctx)