Compare commits

...

6 Commits

Author SHA1 Message Date
neha-Gupta1
328a84ed9f update comments 2023-09-29 15:43:41 +05:30
neha-Gupta1
a32bcfdb87 Merge branch 'updateKopiaPassword' of https://github.com/alcionai/corso into updateKopiaPassword 2023-09-29 15:38:12 +05:30
neha-Gupta1
585a394367 lint code and kopia code movement to kopia package 2023-09-29 15:33:49 +05:30
neha_gupta
a8001f2aa9
Merge branch 'main' into updateKopiaPassword 2023-09-28 22:53:41 +05:30
neha-Gupta1
1b1ddcc713 add test case for repo update 2023-09-28 22:51:54 +05:30
neha-Gupta1
ae66673492 update kopia password 2023-09-28 10:42:07 +05:30
9 changed files with 265 additions and 11 deletions

View File

@ -12,18 +12,20 @@ const (
AWSSessionTokenFN = "aws-session-token" AWSSessionTokenFN = "aws-session-token"
// Corso Flags // Corso Flags
CorsoPassphraseFN = "passphrase" CorsoPassphraseFN = "passphrase"
SucceedIfExistsFN = "succeed-if-exists" UpdateCorsoPassphraseFN = "update-passphrase"
SucceedIfExistsFN = "succeed-if-exists"
) )
var ( var (
BackupIDFV string BackupIDFV string
BackupIDsFV []string BackupIDsFV []string
AWSAccessKeyFV string AWSAccessKeyFV string
AWSSecretAccessKeyFV string AWSSecretAccessKeyFV string
AWSSessionTokenFV string AWSSessionTokenFV string
CorsoPassphraseFV string CorsoPassphraseFV string
SucceedIfExistsFV bool UpdateCorsoPhasephraseFV string
SucceedIfExistsFV bool
) )
// AddMultipleBackupIDsFlag adds the --backups flag. // AddMultipleBackupIDsFlag adds the --backups flag.
@ -73,6 +75,15 @@ func AddCorsoPassphaseFlags(cmd *cobra.Command) {
"Passphrase to protect encrypted repository contents") "Passphrase to protect encrypted repository contents")
} }
// M365 flags
func AddCorsoUpdatePassphraseFlags(cmd *cobra.Command) {
fs := cmd.Flags()
fs.StringVar(&UpdateCorsoPhasephraseFV,
UpdateCorsoPassphraseFN,
"",
"update Corso passphrase for repo")
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Provider // Provider
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -17,6 +17,7 @@ import (
const ( const (
initCommand = "init" initCommand = "init"
connectCommand = "connect" connectCommand = "connect"
updateCommand = "update"
maintenanceCommand = "maintenance" maintenanceCommand = "maintenance"
) )
@ -34,12 +35,14 @@ func AddCommands(cmd *cobra.Command) {
initCmd = initCmd() initCmd = initCmd()
connectCmd = connectCmd() connectCmd = connectCmd()
maintenanceCmd = maintenanceCmd() maintenanceCmd = maintenanceCmd()
updateCmd = updateCmd()
) )
cmd.AddCommand(repoCmd) cmd.AddCommand(repoCmd)
repoCmd.AddCommand(initCmd) repoCmd.AddCommand(initCmd)
repoCmd.AddCommand(connectCmd) repoCmd.AddCommand(connectCmd)
repoCmd.AddCommand(maintenanceCmd) repoCmd.AddCommand(maintenanceCmd)
repoCmd.AddCommand(updateCmd)
flags.AddMaintenanceModeFlag(maintenanceCmd) flags.AddMaintenanceModeFlag(maintenanceCmd)
flags.AddForceMaintenanceFlag(maintenanceCmd) flags.AddForceMaintenanceFlag(maintenanceCmd)
@ -50,6 +53,8 @@ func AddCommands(cmd *cobra.Command) {
addRepoTo(initCmd) addRepoTo(initCmd)
addRepoTo(connectCmd) addRepoTo(connectCmd)
} }
addS3Commands(updateCmd)
} }
// The repo category of commands. // The repo category of commands.
@ -58,7 +63,7 @@ func repoCmd() *cobra.Command {
return &cobra.Command{ return &cobra.Command{
Use: "repo", Use: "repo",
Short: "Manage your repositories", Short: "Manage your repositories",
Long: `Initialize, configure, and connect to your account backup repositories.`, Long: `Initialize, configure, connect and update to your account backup repositories.`,
RunE: handleRepoCmd, RunE: handleRepoCmd,
Args: cobra.NoArgs, Args: cobra.NoArgs,
} }
@ -170,3 +175,20 @@ func getMaintenanceType(t string) (repository.MaintenanceType, error) {
return res, nil return res, nil
} }
// The repo update subcommand.
// `corso repo update <repository> [<flag>...]`
func updateCmd() *cobra.Command {
return &cobra.Command{
Use: updateCommand,
Short: "Update a repository.",
Long: `Update repository configuration and behavior.`,
RunE: handleUpdateCmd,
Args: cobra.NoArgs,
}
}
// Handler for calls to `corso repo init`.
func handleUpdateCmd(cmd *cobra.Command, args []string) error {
return cmd.Help()
}

View File

@ -28,6 +28,11 @@ func addS3Commands(cmd *cobra.Command) *cobra.Command {
case connectCommand: case connectCommand:
c, _ = utils.AddCommand(cmd, s3ConnectCmd()) c, _ = utils.AddCommand(cmd, s3ConnectCmd())
case updateCommand:
update := s3UpdateCmd()
flags.AddCorsoUpdatePassphraseFlags(update)
c, _ = utils.AddCommand(cmd, update)
} }
c.Use = c.Use + " " + s3ProviderCommandUseSuffix c.Use = c.Use + " " + s3ProviderCommandUseSuffix
@ -239,3 +244,60 @@ func connectS3Cmd(cmd *cobra.Command, args []string) error {
return nil return nil
} }
// ---------------------------------------------------------------------------------------------------------
// Update Password
// ---------------------------------------------------------------------------------------------------------
// `corso repo update s3 [<flag>...]`
func s3UpdateCmd() *cobra.Command {
return &cobra.Command{
Use: s3ProviderCommand,
Short: "Update to a S3 repository",
Long: `Update to an existing S3 repository.`,
RunE: updateS3Cmd,
Args: cobra.NoArgs,
Example: s3ProviderCommandConnectExamples,
}
}
// updates to an existing s3 repo.
// currently just updating Kopia password
func updateS3Cmd(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
cfg, err := config.GetConfigRepoDetails(
ctx,
storage.ProviderS3,
true,
true,
flags.S3FlagOverrides(cmd))
if err != nil {
return Only(ctx, err)
}
repoID := cfg.RepoID
if len(repoID) == 0 {
repoID = events.RepoIDNotFound
}
opts := utils.ControlWithConfig(cfg)
r, err := repository.New(
ctx,
cfg.Account,
cfg.Storage,
opts,
repoID)
if err != nil {
return Only(ctx, clues.Wrap(err, "Failed to create a repository controller"))
}
if err := r.UpdatePassword(ctx, flags.UpdateCorsoPhasephraseFV); err != nil {
return Only(ctx, clues.Wrap(err, "Failed to update s3"))
}
Infof(ctx, "Updated repo password.")
return nil
}

View File

@ -289,3 +289,80 @@ func (suite *S3E2ESuite) TestConnectS3Cmd_BadPrefix() {
err = cmd.ExecuteContext(ctx) err = cmd.ExecuteContext(ctx)
require.Error(t, err, clues.ToCore(err)) require.Error(t, err, clues.ToCore(err))
} }
func (suite *S3E2ESuite) TestUpdateS3Cmd() {
t := suite.T()
ctx, flush := tester.NewContext(t)
defer flush()
st := storeTD.NewPrefixedS3Storage(t)
sc, err := st.StorageConfig()
require.NoError(t, err, clues.ToCore(err))
cfg := sc.(*storage.S3Config)
vpr, configFP := tconfig.MakeTempTestConfigClone(t, nil)
ctx = config.SetViper(ctx, vpr)
cmd := cliTD.StubRootCmd(
"repo", "init", "s3",
"--config-file", configFP,
"--prefix", cfg.Prefix)
cli.BuildCommandTree(cmd)
// run the command
err = cmd.ExecuteContext(ctx)
require.NoError(t, err, clues.ToCore(err))
// connect with old passphrase
cmd = cliTD.StubRootCmd(
"repo", "connect", "s3",
"--config-file", configFP,
"--bucket", cfg.Bucket,
"--prefix", cfg.Prefix)
cli.BuildCommandTree(cmd)
// run the command
err = cmd.ExecuteContext(ctx)
require.NoError(t, err, clues.ToCore(err))
cmd = cliTD.StubRootCmd(
"repo", "update", "s3",
"--config-file", configFP,
"--bucket", cfg.Bucket,
"--prefix", cfg.Prefix,
"--update-passphrase", "newpass")
cli.BuildCommandTree(cmd)
// run the command
err = cmd.ExecuteContext(ctx)
require.NoError(t, err, clues.ToCore(err))
// connect again with new passphrase
cmd = cliTD.StubRootCmd(
"repo", "connect", "s3",
"--config-file", configFP,
"--bucket", cfg.Bucket,
"--prefix", cfg.Prefix,
"--passphrase", "newpass")
cli.BuildCommandTree(cmd)
// run the command
err = cmd.ExecuteContext(ctx)
require.NoError(t, err, clues.ToCore(err))
// connect with old passphrase - it will fail
cmd = cliTD.StubRootCmd(
"repo", "connect", "s3",
"--config-file", configFP,
"--bucket", cfg.Bucket,
"--prefix", cfg.Prefix)
cli.BuildCommandTree(cmd)
// run the command
err = cmd.ExecuteContext(ctx)
require.Error(t, err, clues.ToCore(err))
}

View File

@ -31,6 +31,7 @@ func (suite *S3Suite) TestAddS3Commands() {
}{ }{
{"init s3", initCommand, expectUse, s3InitCmd().Short, initS3Cmd}, {"init s3", initCommand, expectUse, s3InitCmd().Short, initS3Cmd},
{"connect s3", connectCommand, expectUse, s3ConnectCmd().Short, connectS3Cmd}, {"connect s3", connectCommand, expectUse, s3ConnectCmd().Short, connectS3Cmd},
{"update s3", updateCommand, expectUse, s3UpdateCmd().Short, updateS3Cmd},
} }
for _, test := range table { for _, test := range table {
suite.Run(test.name, func() { suite.Run(test.name, func() {

View File

@ -31,6 +31,7 @@ const (
CorsoStart = "Corso Start" CorsoStart = "Corso Start"
RepoInit = "Repo Init" RepoInit = "Repo Init"
RepoConnect = "Repo Connect" RepoConnect = "Repo Connect"
RepoUpdate = "Repo Update"
BackupStart = "Backup Start" BackupStart = "Backup Start"
BackupEnd = "Backup End" BackupEnd = "Backup End"
RestoreStart = "Restore Start" RestoreStart = "Restore Start"

View File

@ -578,3 +578,17 @@ func (w *conn) LoadSnapshot(
func (w *conn) SnapshotRoot(man *snapshot.Manifest) (fs.Entry, error) { func (w *conn) SnapshotRoot(man *snapshot.Manifest) (fs.Entry, error) {
return snapshotfs.SnapshotRoot(w.Repository, man) return snapshotfs.SnapshotRoot(w.Repository, man)
} }
func (w *conn) UpdatePassword(ctx context.Context, password string, opts repository.Options) error {
kopiaRef := NewConn(w.storage)
if err := kopiaRef.Connect(ctx, opts); err != nil {
return clues.Wrap(err, "connecting kopia client")
}
defer kopiaRef.Close(ctx)
repository := kopiaRef.Repository.(repo.DirectRepository)
err := repository.FormatManager().ChangePassword(ctx, password)
return errors.Wrap(err, "unable to update password")
}

View File

@ -128,7 +128,7 @@ func New(
s storage.Storage, s storage.Storage,
opts control.Options, opts control.Options,
configFileRepoID string, configFileRepoID string,
) (repo *repository, err error) { ) (singleRepo *repository, err error) {
ctx = clues.Add( ctx = clues.Add(
ctx, ctx,
"acct_provider", acct.Provider.String(), "acct_provider", acct.Provider.String(),
@ -272,6 +272,41 @@ func (r *repository) Connect(ctx context.Context) (err error) {
return nil return nil
} }
// UpdatePassword will-
// - connect to the provider storage using existing password
// - update the repo with new password
func (r *repository) UpdatePassword(ctx context.Context, password string) (err error) {
ctx = clues.Add(
ctx,
"acct_provider", r.Account.Provider.String(),
"acct_id", clues.Hide(r.Account.ID()),
"storage_provider", r.Storage.Provider.String())
defer func() {
if crErr := crash.Recovery(ctx, recover(), "repo connect"); crErr != nil {
err = crErr
}
}()
progressBar := observe.MessageWithCompletion(ctx, "Connecting to repository")
defer close(progressBar)
kopiaRef := kopia.NewConn(r.Storage)
if err := kopiaRef.Connect(ctx, r.Opts.Repo); err != nil {
return clues.Wrap(err, "connecting kopia client")
}
if err := kopiaRef.UpdatePassword(ctx, password, r.Opts.Repo); err != nil {
return clues.Wrap(err, "updating on kopia")
}
defer kopiaRef.Close(ctx)
r.Bus.Event(ctx, events.RepoUpdate, nil)
return nil
}
func (r *repository) Close(ctx context.Context) error { func (r *repository) Close(ctx context.Context) error {
if err := r.Bus.Close(); err != nil { if err := r.Bus.Close(); err != nil {
logger.Ctx(ctx).With("err", err).Debugw("closing the event bus", clues.In(ctx).Slice()...) logger.Ctx(ctx).With("err", err).Debugw("closing the event bus", clues.In(ctx).Slice()...)

View File

@ -236,6 +236,37 @@ func (suite *RepositoryIntegrationSuite) TestConnect() {
assert.NoError(t, err, clues.ToCore(err)) assert.NoError(t, err, clues.ToCore(err))
} }
func (suite *RepositoryIntegrationSuite) TestRepository_UpdatePassword() {
t := suite.T()
ctx, flush := tester.NewContext(t)
defer flush()
// need to initialize the repository before we can test connecting to it.
st := storeTD.NewPrefixedS3Storage(t)
r, err := New(
ctx,
account.Account{},
st,
control.DefaultOptions(),
NewRepoID)
require.NoError(t, err, clues.ToCore(err))
err = r.Initialize(ctx, ctrlRepo.Retention{})
require.NoError(t, err, clues.ToCore(err))
// now re-connect
err = r.Connect(ctx)
assert.NoError(t, err, clues.ToCore(err))
err = r.UpdatePassword(ctx, "newpass")
require.NoError(t, err, clues.ToCore(err))
// now reconnect with new pass
err = r.Connect(ctx)
assert.Error(t, err, clues.ToCore(err))
}
func (suite *RepositoryIntegrationSuite) TestConnect_sameID() { func (suite *RepositoryIntegrationSuite) TestConnect_sameID() {
t := suite.T() t := suite.T()