Skip to content

Commit

Permalink
Added AWS cloud storage functionality
Browse files Browse the repository at this point in the history
* Added AWS cloud functionality
* adding init flow
* error fix
* read aws default creds directly via sdk
  • Loading branch information
shubhamvernekar authored Nov 20, 2023
1 parent f36e031 commit 0fc6461
Show file tree
Hide file tree
Showing 10 changed files with 348 additions and 72 deletions.
30 changes: 28 additions & 2 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/scalescape/dolores/config"
"github.com/scalescape/dolores/store/aws"
"github.com/scalescape/dolores/store/google"
)

Expand Down Expand Up @@ -106,12 +107,37 @@ func (c *Client) GetSecretList(_ SecretListConfig) ([]SecretObject, error) {
return objs, nil
}

func getStore(ctx context.Context, cfg config.Client) (clouldStore, error) {

Check failure on line 110 in client/client.go

View workflow job for this annotation

GitHub Actions / golangci-lint

getStore returns interface (github.com/scalescape/dolores/client.clouldStore) (ireturn)
var store clouldStore
var err error
switch cfg.Provider {
case config.AWS:
{
store, err = aws.NewStore(ctx)
if err != nil {
return nil, err
}
}
case config.GCS:
{
gcfg := google.Config{ServiceAccountFile: cfg.Cloud.ApplicationCredentials}
store, err = google.NewStore(ctx, gcfg)
if err != nil {
return nil, err
}
}
default:
err = fmt.Errorf("failed to get store: %w", config.ErrCloudProviderNotFound)
}

return store, err
}

func New(ctx context.Context, cfg config.Client) (*Client, error) {
if err := cfg.Valid(); err != nil {
return nil, err
}
gcfg := google.Config{ServiceAccountFile: cfg.Google.ApplicationCredentials}
st, err := google.NewStore(ctx, gcfg)
st, err := getStore(ctx, cfg)
if err != nil {
return nil, err
}
Expand Down
12 changes: 6 additions & 6 deletions client/gcs_service.go → client/cloud_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ import (

"github.com/rs/zerolog/log"
"github.com/scalescape/dolores/config"
"github.com/scalescape/dolores/store/google"
"github.com/scalescape/dolores/store/cloud"
)

var ErrInvalidPublicKeys = errors.New("invalid public keys")

const metadataFile = "dolores.md"

type Service struct {
store gcsStore
store clouldStore
}

type gcsStore interface {
type clouldStore interface {
WriteToObject(ctx context.Context, bucketName, fileName string, data []byte) error
ReadObject(ctx context.Context, bucketName, fileName string) ([]byte, error)
ListObject(ctx context.Context, bucketName, path string) ([]google.Object, error)
ListObject(ctx context.Context, bucketName, path string) ([]cloud.Object, error)
ExistsObject(ctx context.Context, bucketName, fileName string) (bool, error)
}

Expand Down Expand Up @@ -138,14 +138,14 @@ func (s Service) saveObject(ctx context.Context, bucket, fname string, md any) e
return s.store.WriteToObject(ctx, bucket, fname, data)
}

func (s Service) ListObject(ctx context.Context, bucket, path string) ([]google.Object, error) {
func (s Service) ListObject(ctx context.Context, bucket, path string) ([]cloud.Object, error) {
resp, err := s.store.ListObject(ctx, bucket, path)
if err != nil {
return nil, err
}
return resp, nil
}

func NewService(st gcsStore) Service {
func NewService(st clouldStore) Service {
return Service{store: st}
}
9 changes: 5 additions & 4 deletions client/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

"github.com/scalescape/dolores/client"
"github.com/scalescape/dolores/config"
"github.com/scalescape/dolores/store/google"
"github.com/scalescape/dolores/store/cloud"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -39,9 +39,9 @@ func (m *mockGCS) ReadObject(ctx context.Context, bucketName, fileName string) (
return args.Get(0).([]byte), args.Error(1)
}

func (m *mockGCS) ListObject(ctx context.Context, bucketName, path string) ([]google.Object, error) {
func (m *mockGCS) ListObject(ctx context.Context, bucketName, path string) ([]cloud.Object, error) {
args := m.Called(ctx, bucketName, path)
return args.Get(0).([]google.Object), args.Error(1)
return args.Get(0).([]cloud.Object), args.Error(1)
}

func (m *mockGCS) ExistsObject(ctx context.Context, bucketName, fileName string) (bool, error) {
Expand Down Expand Up @@ -69,7 +69,8 @@ func (s *serviceSuite) TestShouldNotOverwriteMetadata() {
cfg := client.Configuration{
PublicKey: "public_key",
Metadata: config.Metadata{Location: "secrets"},
UserID: "test_user"}
UserID: "test_user",
}
s.gcs.On("ExistsObject", mock.AnythingOfType("context.backgroundCtx"), s.bucket, name).Return(true, nil).Once()
s.gcs.On("WriteToObject", mock.AnythingOfType("context.backgroundCtx"), s.bucket, "secrets/keys/test_user.key", []byte(cfg.PublicKey)).Return(nil).Once()

Expand Down
77 changes: 56 additions & 21 deletions cmd/dolores/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ func NewInitCommand(newCli GetClient) *cli.Command {
}

type Input struct {
CloudProvider string `survey:"cloud_provider"`
UserID string `survey:"user_id"`
Bucket string
Location string
ApplicationCredentials string `survey:"google_creds"`
ApplicationCredentials string `survey:"creds"`
}

func (inp Input) ToMetadata(env string) config.Metadata {
return config.Metadata{
CloudProvider: inp.CloudProvider,
Bucket: inp.Bucket,
Location: inp.Location,
CreatedAt: time.Now(),
Expand All @@ -57,13 +59,61 @@ func (inp Input) ToMetadata(env string) config.Metadata {
}
}

func (c *InitCommand) getCred(res *Input) error {
qs := []*survey.Question{}

switch res.CloudProvider {
case config.GCS:
{
credFile := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
if credFile != "" {
qs = append(qs, &survey.Question{
Name: "creds",
Validate: survey.Required,
Prompt: &survey.Select{
Message: "Use GOOGLE_APPLICATION_CREDENTIALS env as credentials file",
Options: []string{credFile},
},
})
} else {
qs = append(qs, &survey.Question{
Name: "creds",
Prompt: &survey.Input{
Message: "Enter google service account file path",
},
Validate: survey.Required,
})
}
}
case config.AWS:
{
res.ApplicationCredentials = "aws_default"
return nil
}
}

credRes := new(Input)
if err := survey.Ask(qs, credRes); err != nil {
return fmt.Errorf("failed to get appropriate input: %w", err)
}
res.ApplicationCredentials = credRes.ApplicationCredentials
return nil
}

func (c *InitCommand) getData(env string) (*Input, error) {
credFile := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
qs := []*survey.Question{
{
Name: "cloud_provider",
Validate: survey.Required,
Prompt: &survey.Select{
Message: "Select Cloud provider",
Options: []string{config.AWS, config.GCS},
},
},
{
Name: "bucket",
Prompt: &survey.Input{
Message: "Enter the GCS bucket name:",
Message: "Enter the bucket name:",
},
Validate: survey.Required,
},
Expand All @@ -84,28 +134,13 @@ func (c *InitCommand) getData(env string) (*Input, error) {
},
},
}
if credFile != "" {
qs = append(qs, &survey.Question{
Name: "google_creds",
Validate: survey.Required,
Prompt: &survey.Select{
Message: "Use GOOGLE_APPLICATION_CREDENTIALS env as credentials file",
Options: []string{credFile},
},
})
} else {
qs = append(qs, &survey.Question{
Name: "google_creds",
Prompt: &survey.Input{
Message: "Enter google service account file path",
},
Validate: survey.Required,
})
}
res := new(Input)
if err := survey.Ask(qs, res); err != nil {
return nil, fmt.Errorf("failed to get appropriate input: %w", err)
}
if err := c.getCred(res); err != nil {
return nil, fmt.Errorf("failed to get appropriate input: %w", err)
}
return res, nil
}

Expand Down
41 changes: 28 additions & 13 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ import (
)

var (
ErrInvalidGoogleCreds = errors.New("invalid google application credentials")
ErrInvalidStorageBucket = errors.New("invalid storage bucket")
ErrInvalidKeyFile = errors.New("invalid key file")
ErrInvalidGoogleCreds = errors.New("invalid google application credentials")
ErrInvalidStorageBucket = errors.New("invalid storage bucket")
ErrInvalidKeyFile = errors.New("invalid key file")
ErrCloudProviderNotFound = errors.New("cloud provider not found")
)

var (
AWS = "AWS"
GCS = "GCS"
)

type CtxKey string
Expand All @@ -27,13 +33,14 @@ var (
File = filepath.Join(Dir, "dolores.json")
)

type Google struct {
type Cloud struct {
ApplicationCredentials string `split_words:"true"`
StorageBucket string `split_words:"true"`
StoragePrefix string
}

type Metadata struct {
CloudProvider string `json:"cloud_provider"`
Bucket string `json:"bucket"`
Location string `json:"location"`
Environment string `json:"environment"`
Expand All @@ -42,18 +49,22 @@ type Metadata struct {
}

type Client struct {
Google
Cloud
Provider string
}

func (c Client) BucketName() string {
return c.Google.StorageBucket
return c.Cloud.StorageBucket
}

func (c Client) Valid() error {
if c.Google.ApplicationCredentials == "" {
if c.Provider == "" {
return ErrCloudProviderNotFound
}
if c.Cloud.ApplicationCredentials == "" {
return ErrInvalidGoogleCreds
}
if c.Google.StorageBucket == "" {
if c.Cloud.StorageBucket == "" {
return ErrInvalidStorageBucket
}
return nil
Expand All @@ -65,23 +76,27 @@ func LoadClient(ctx context.Context, env string) (Client, error) {
if err != nil {
return Client{}, fmt.Errorf("dolores not initialized yet: %w", err)
}
if err := envconfig.Process("GOOGLE", &cfg.Google); err != nil {
if err := envconfig.Process("GOOGLE", &cfg.Cloud); err != nil {
return Client{}, fmt.Errorf("processing config: %w", err)
}

md := d.Environments[env].Metadata
if cfg.Google.ApplicationCredentials == "" {
if cloudProvider := md.CloudProvider; cloudProvider != "" {
cfg.Provider = cloudProvider
}

if cfg.Cloud.ApplicationCredentials == "" {
if creds := md.ApplicationCredentials; creds != "" {
cfg.Google.ApplicationCredentials = creds
cfg.Cloud.ApplicationCredentials = creds
}
}

if bucket := md.Bucket; bucket != "" {
cfg.Google.StorageBucket = bucket
cfg.Cloud.StorageBucket = bucket
}

if location := md.Location; location != "" {
cfg.Google.StoragePrefix = location
cfg.Cloud.StoragePrefix = location
}

if err := cfg.Valid(); err != nil {
Expand Down
29 changes: 24 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ require (
cloud.google.com/go/storage v1.30.1
filippo.io/age v1.1.1
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/aws/aws-sdk-go-v2/config v1.23.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.42.1
github.com/kelseyhightower/envconfig v1.4.0
github.com/rs/zerolog v1.29.1
github.com/scalescape/go-metrics v0.0.0-20230825040750-1888415fe69a
Expand All @@ -14,11 +16,28 @@ require (
google.golang.org/api v0.129.0
)

require github.com/aws/aws-sdk-go-v2/credentials v1.15.2 // indirect

require (
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/compute v1.19.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v0.13.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.22.2
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.6.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.25.1 // indirect
github.com/aws/smithy-go v1.16.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cactus/go-statsd-client/v5 v5.0.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
Expand All @@ -45,12 +64,12 @@ require (
github.com/stretchr/objx v0.5.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.9.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/term v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
Expand Down
Loading

0 comments on commit 0fc6461

Please sign in to comment.