add e2e wiring of cli to kopia (#77)
* add e2e wiring of cli to kopia Now that pkg/storage and internal/kopia are in place, we can wire up the init flow from the cli all the way to kopia. Testing harness for this functionality still needs investigation afterward. * factor out awsVars struct for s3Cfg
This commit is contained in:
parent
569ba524ac
commit
548eb1be72
@ -61,7 +61,7 @@ var connectCmd = &cobra.Command{
|
||||
Use: connectCommand,
|
||||
Short: "Connect to a repository.",
|
||||
Long: `Connect to an existing repository.`,
|
||||
Run: handleInitCmd,
|
||||
Run: handleConnectCmd,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/alcionai/corso/pkg/repository"
|
||||
"github.com/alcionai/corso/pkg/repository/s3"
|
||||
"github.com/alcionai/corso/pkg/storage"
|
||||
)
|
||||
|
||||
// s3 bucket info from flags
|
||||
@ -45,26 +45,23 @@ var s3InitCmd = &cobra.Command{
|
||||
// initializes a s3 repo.
|
||||
func initS3Cmd(cmd *cobra.Command, args []string) {
|
||||
mv := getM365Vars()
|
||||
av := getAwsVars()
|
||||
s3Cfg := makeS3Config()
|
||||
fmt.Printf(
|
||||
"Called -\n`corso repo init s3`\nbucket:\t%s\nkey:\t%s\n356Client:\t%s\nfound 356Secret:\t%v\nfound awsSecret:\t%v\n",
|
||||
bucket,
|
||||
av.accessKey,
|
||||
s3Cfg.Bucket,
|
||||
s3Cfg.AccessKey,
|
||||
mv.clientID,
|
||||
len(mv.clientSecret) > 0,
|
||||
len(av.accessSecret) > 0)
|
||||
len(s3Cfg.SecretKey) > 0)
|
||||
|
||||
_, err := repository.Initialize(
|
||||
cmd.Context(),
|
||||
repository.ProviderS3,
|
||||
repository.Account{
|
||||
TenantID: mv.tenantID,
|
||||
ClientID: mv.clientID,
|
||||
ClientSecret: mv.clientSecret,
|
||||
},
|
||||
s3.NewConfig(av.bucket, av.accessKey, av.accessSecret),
|
||||
)
|
||||
if err != nil {
|
||||
a := repository.Account{
|
||||
TenantID: mv.tenantID,
|
||||
ClientID: mv.clientID,
|
||||
ClientSecret: mv.clientSecret,
|
||||
}
|
||||
s := storage.NewStorage(storage.ProviderS3, s3Cfg)
|
||||
|
||||
if _, err := repository.Initialize(cmd.Context(), a, s); err != nil {
|
||||
fmt.Printf("Failed to initialize a new S3 repository: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -82,47 +79,37 @@ var s3ConnectCmd = &cobra.Command{
|
||||
// connects to an existing s3 repo.
|
||||
func connectS3Cmd(cmd *cobra.Command, args []string) {
|
||||
mv := getM365Vars()
|
||||
av := getAwsVars()
|
||||
s3Cfg := makeS3Config()
|
||||
fmt.Printf(
|
||||
"Called -\n`corso repo connect s3`\nbucket:\t%s\nkey:\t%s\n356Client:\t%s\nfound 356Secret:\t%v\nfound awsSecret:\t%v\n",
|
||||
bucket,
|
||||
accessKey,
|
||||
s3Cfg.Bucket,
|
||||
s3Cfg.AccessKey,
|
||||
mv.clientID,
|
||||
len(mv.clientSecret) > 0,
|
||||
len(av.accessSecret) > 0)
|
||||
len(s3Cfg.SecretKey) > 0)
|
||||
|
||||
_, err := repository.Connect(
|
||||
cmd.Context(),
|
||||
repository.ProviderS3,
|
||||
repository.Account{
|
||||
TenantID: mv.tenantID,
|
||||
ClientID: mv.clientID,
|
||||
ClientSecret: mv.clientSecret,
|
||||
},
|
||||
s3.NewConfig(av.bucket, av.accessKey, av.accessSecret),
|
||||
)
|
||||
if err != nil {
|
||||
a := repository.Account{
|
||||
TenantID: mv.tenantID,
|
||||
ClientID: mv.clientID,
|
||||
ClientSecret: mv.clientSecret,
|
||||
}
|
||||
s := storage.NewStorage(storage.ProviderS3, s3Cfg)
|
||||
|
||||
if _, err := repository.Connect(cmd.Context(), a, s); err != nil {
|
||||
fmt.Printf("Failed to connect to the S3 repository: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// aggregates aws details from flag and env_var values.
|
||||
type awsVars struct {
|
||||
accessKey string
|
||||
accessSecret string
|
||||
bucket string
|
||||
}
|
||||
|
||||
// helper for aggregating aws connection details.
|
||||
func getAwsVars() awsVars {
|
||||
func makeS3Config() storage.S3Config {
|
||||
ak := os.Getenv("AWS_ACCESS_KEY_ID")
|
||||
if len(accessKey) > 0 {
|
||||
ak = accessKey
|
||||
}
|
||||
return awsVars{
|
||||
accessKey: ak,
|
||||
accessSecret: os.Getenv("AWS_SECRET_ACCESS_KEY"),
|
||||
bucket: bucket,
|
||||
return storage.S3Config{
|
||||
AccessKey: ak,
|
||||
SecretKey: os.Getenv("AWS_SECRET_ACCESS_KEY"),
|
||||
Bucket: bucket,
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,8 +4,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/alcionai/corso/internal/kopia"
|
||||
"github.com/alcionai/corso/pkg/storage"
|
||||
"github.com/google/uuid"
|
||||
"github.com/kopia/kopia/repo/blob"
|
||||
)
|
||||
|
||||
type repoProvider int
|
||||
@ -22,9 +23,8 @@ type Repository struct {
|
||||
CreatedAt time.Time
|
||||
Version string // in case of future breaking changes
|
||||
|
||||
Provider repoProvider // must be repository.S3Provider
|
||||
Account Account // the user's m365 account connection details
|
||||
Config Config // provider-based configuration details
|
||||
Account Account // the user's m365 account connection details
|
||||
Storage storage.Storage // the storage provider details and configuration
|
||||
}
|
||||
|
||||
// Account holds the user's m365 account details.
|
||||
@ -34,10 +34,6 @@ type Account struct {
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
type Config interface {
|
||||
KopiaStorage(ctx context.Context, create bool) (blob.Storage, error)
|
||||
}
|
||||
|
||||
// Initialize will:
|
||||
// * validate the m365 account & secrets
|
||||
// * connect to the m365 account to ensure communication capability
|
||||
@ -48,16 +44,18 @@ type Config interface {
|
||||
// * return the connected repository
|
||||
func Initialize(
|
||||
ctx context.Context,
|
||||
provider repoProvider,
|
||||
acct Account,
|
||||
cfg Config,
|
||||
storage storage.Storage,
|
||||
) (Repository, error) {
|
||||
k := kopia.New(storage)
|
||||
if err := k.Initialize(ctx); err != nil {
|
||||
return Repository{}, err
|
||||
}
|
||||
r := Repository{
|
||||
ID: uuid.New(),
|
||||
Version: "v1",
|
||||
Provider: provider,
|
||||
Account: acct,
|
||||
Config: cfg,
|
||||
ID: uuid.New(),
|
||||
Version: "v1",
|
||||
Account: acct,
|
||||
Storage: storage,
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
@ -69,16 +67,18 @@ func Initialize(
|
||||
// * return the connected repository
|
||||
func Connect(
|
||||
ctx context.Context,
|
||||
provider repoProvider,
|
||||
acct Account,
|
||||
cfg Config,
|
||||
storage storage.Storage,
|
||||
) (Repository, error) {
|
||||
k := kopia.New(storage)
|
||||
if err := k.Connect(ctx); err != nil {
|
||||
return Repository{}, err
|
||||
}
|
||||
// todo: ID and CreatedAt should get retrieved from a stored kopia config.
|
||||
r := Repository{
|
||||
Version: "v1",
|
||||
Provider: provider,
|
||||
Account: acct,
|
||||
Config: cfg,
|
||||
Version: "v1",
|
||||
Account: acct,
|
||||
Storage: storage,
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@ -2,37 +2,55 @@ package repository_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kopia/kopia/repo/blob"
|
||||
|
||||
"github.com/alcionai/corso/pkg/repository"
|
||||
"github.com/alcionai/corso/pkg/storage"
|
||||
)
|
||||
|
||||
type testConfig struct{}
|
||||
|
||||
func (tc testConfig) KopiaStorage(ctx context.Context, create bool) (blob.Storage, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
_, err := repository.Initialize(
|
||||
context.Background(),
|
||||
repository.ProviderUnknown,
|
||||
repository.Account{},
|
||||
testConfig{})
|
||||
if err != nil {
|
||||
t.Fatalf("didn't expect initialize to error, got [%v]", err)
|
||||
table := []struct {
|
||||
storage storage.Storage
|
||||
account repository.Account
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
storage.NewStorage(storage.ProviderUnknown),
|
||||
repository.Account{},
|
||||
"provider details are required",
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
t.Run(test.expectedErr, func(t *testing.T) {
|
||||
_, err := repository.Initialize(context.Background(), test.account, test.storage)
|
||||
if err == nil || !strings.Contains(err.Error(), test.expectedErr) {
|
||||
t.Fatalf("expected error with [%s], got [%v]", test.expectedErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// repository.Connect involves end-to-end communication with kopia, therefore this only
|
||||
// tests expected error cases from
|
||||
func TestConnect(t *testing.T) {
|
||||
_, err := repository.Connect(
|
||||
context.Background(),
|
||||
repository.ProviderUnknown,
|
||||
repository.Account{},
|
||||
testConfig{})
|
||||
if err != nil {
|
||||
t.Fatalf("didn't expect connect to error, got [%v]", err)
|
||||
table := []struct {
|
||||
storage storage.Storage
|
||||
account repository.Account
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
storage.NewStorage(storage.ProviderUnknown),
|
||||
repository.Account{},
|
||||
"provider details are required",
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
t.Run(test.expectedErr, func(t *testing.T) {
|
||||
_, err := repository.Connect(context.Background(), test.account, test.storage)
|
||||
if err == nil || !strings.Contains(err.Error(), test.expectedErr) {
|
||||
t.Fatalf("expected error with [%s], got [%v]", test.expectedErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user