add --succeed-on-exists flag to make s3 repo init idempotent (#324)

* [Minor #323] add --success-on-exists flag to make  idempotent

Co-authored-by: ryanfkeepers <ryanfkeepers@gmail.com>
Co-authored-by: Keepers <104464746+ryanfkeepers@users.noreply.github.com>
This commit is contained in:
Sidhartha Mani 2022-07-25 11:42:24 -07:00 committed by GitHub
parent e4c7538531
commit 6a9ccf2a51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 4 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/alcionai/corso/cli/config" "github.com/alcionai/corso/cli/config"
"github.com/alcionai/corso/cli/utils" "github.com/alcionai/corso/cli/utils"
"github.com/alcionai/corso/internal/kopia"
"github.com/alcionai/corso/pkg/account" "github.com/alcionai/corso/pkg/account"
"github.com/alcionai/corso/pkg/credentials" "github.com/alcionai/corso/pkg/credentials"
"github.com/alcionai/corso/pkg/logger" "github.com/alcionai/corso/pkg/logger"
@ -18,10 +19,11 @@ import (
// s3 bucket info from flags // s3 bucket info from flags
var ( var (
accessKey string accessKey string
bucket string bucket string
endpoint string endpoint string
prefix string prefix string
succeedIfExists bool
) )
// called by repo.go to map parent subcommands to provider-specific handling. // called by repo.go to map parent subcommands to provider-specific handling.
@ -41,6 +43,10 @@ func addS3Commands(parent *cobra.Command) *cobra.Command {
cobra.CheckErr(c.MarkFlagRequired("bucket")) cobra.CheckErr(c.MarkFlagRequired("bucket"))
fs.StringVar(&endpoint, "endpoint", "s3.amazonaws.com", "Server endpoint for S3 communication.") fs.StringVar(&endpoint, "endpoint", "s3.amazonaws.com", "Server endpoint for S3 communication.")
fs.StringVar(&prefix, "prefix", "", "Prefix applied to objects in the bucket.") fs.StringVar(&prefix, "prefix", "", "Prefix applied to objects in the bucket.")
fs.BoolVar(&succeedIfExists, "succeed-if-exists", false, "Exit with success if the repo has already been initialized.")
// In general, we don't want to expose this flag to users and have them mistake it
// for a broad-scale idempotency solution. We can un-hide it later the need arises.
cobra.CheckErr(fs.MarkHidden("succeed-if-exists"))
return c return c
} }
@ -88,6 +94,9 @@ func initS3Cmd(cmd *cobra.Command, args []string) error {
r, err := repository.Initialize(ctx, a, s) r, err := repository.Initialize(ctx, a, s)
if err != nil { if err != nil {
if succeedIfExists && kopia.IsRepoAlreadyExistsError(err) {
return nil
}
return errors.Wrap(err, "Failed to initialize a new S3 repository") return errors.Wrap(err, "Failed to initialize a new S3 repository")
} }
defer utils.CloseRepo(ctx, r) defer utils.CloseRepo(ctx, r)

View File

@ -8,6 +8,7 @@ import (
"github.com/kopia/kopia/repo/blob" "github.com/kopia/kopia/repo/blob"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/alcionai/corso/internal/common"
"github.com/alcionai/corso/pkg/storage" "github.com/alcionai/corso/pkg/storage"
) )
@ -20,6 +21,19 @@ var (
errConnect = errors.New("connecting repo") errConnect = errors.New("connecting repo")
) )
type ErrorRepoAlreadyExists struct {
common.Err
}
func RepoAlreadyExistsError(e error) error {
return ErrorRepoAlreadyExists{*common.EncapsulateError(e)}
}
func IsRepoAlreadyExistsError(e error) bool {
var erae ErrorRepoAlreadyExists
return errors.As(e, &erae)
}
type conn struct { type conn struct {
storage storage.Storage storage storage.Storage
repo.Repository repo.Repository
@ -47,6 +61,9 @@ func (w *conn) Initialize(ctx context.Context) error {
// todo - issue #75: nil here should be a storage.NewRepoOptions() // todo - issue #75: nil here should be a storage.NewRepoOptions()
if err = repo.Initialize(ctx, bst, nil, cfg.CorsoPassword); err != nil { if err = repo.Initialize(ctx, bst, nil, cfg.CorsoPassword); err != nil {
if errors.Is(err, repo.ErrAlreadyInitialized) {
return RepoAlreadyExistsError(err)
}
return errors.Wrap(err, errInit.Error()) return errors.Wrap(err, errInit.Error())
} }