Skip to content

Commit

Permalink
create metadata file if it doesn't exists in remote gcs
Browse files Browse the repository at this point in the history
  • Loading branch information
devdinu committed Jul 3, 2023
1 parent 0db5055 commit 77c7120
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 34 deletions.
58 changes: 44 additions & 14 deletions client/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,36 @@ type gcsStore interface {
WriteToObject(ctx context.Context, bucketName, fileName string, data []byte) error
ReadObject(ctx context.Context, bucketName, fileName string) ([]byte, error)
ListOjbect(ctx context.Context, bucketName, path string) ([]string, error)
ExistsObject(ctx context.Context, bucketName, fileName string) (bool, error)
}

type Configuration struct {
Metadata config.Metadata
PublicKey string
UserID string
}

func (s Service) Init(ctx context.Context, bucket string, cfg Configuration) error {
// saving metadata and append key to google cloud storage
if cfg.PublicKey != "" {
pubKey := fmt.Sprintf("%s/keys/%s.key", cfg.Metadata.Location, cfg.UserID)
if err := s.uploadPubKey(ctx, bucket, pubKey, cfg.PublicKey); err != nil {
return fmt.Errorf("error writing public key: %w", err)
}
}
exists, err := s.store.ExistsObject(ctx, bucket, metadataFile)
if err != nil {
return err
}
if exists {
log.Info().Msgf("metadata already configured in remote")
return nil
}
if err := s.saveObject(ctx, bucket, metadataFile, cfg.Metadata); err != nil {
log.Error().Msgf("error writing metadta: %v", err)
return err
}
return nil
}

func (s Service) Upload(ctx context.Context, req EncryptedConfig, bucket string) error {
Expand Down Expand Up @@ -62,18 +92,6 @@ func (s Service) GetOrgPublicKeys(ctx context.Context, env, bucketName, path str
return keys, nil
}

func (s Service) getObjectPrefix(ctx context.Context, env, bucket string) (string, error) {
md, err := s.readMetadata(ctx, bucket, metadataFile)
if err != nil {
return "", fmt.Errorf("failed to read metadata: %w", err)
}
var meta config.Metadata
if err := json.Unmarshal(md, &meta); err != nil {
return "", fmt.Errorf("failed to parse metadata file: %w", err)
}
return meta.Location, nil
}

func (s Service) FetchConfig(ctx context.Context, bucket string, req FetchSecretRequest) ([]byte, error) {
fileName := req.Name
prefix, err := s.getObjectPrefix(ctx, req.Environment, bucket)
Expand All @@ -90,7 +108,19 @@ func (s Service) FetchConfig(ctx context.Context, bucket string, req FetchSecret
return data, nil
}

func (s Service) UploadPubKey(ctx context.Context, bucket string, path, key string) error {
func (s Service) getObjectPrefix(ctx context.Context, env, bucket string) (string, error) {
md, err := s.readMetadata(ctx, bucket, metadataFile)
if err != nil {
return "", fmt.Errorf("failed to read metadata: %w", err)
}
var meta config.Metadata
if err := json.Unmarshal(md, &meta); err != nil {
return "", fmt.Errorf("failed to parse metadata file: %w", err)
}
return meta.Location, nil
}

func (s Service) uploadPubKey(ctx context.Context, bucket string, path, key string) error {
return s.store.WriteToObject(ctx, bucket, path, []byte(key))
}

Expand All @@ -99,7 +129,7 @@ func (s Service) readMetadata(ctx context.Context, bucket, mdf string) ([]byte,
return s.store.ReadObject(ctx, bucket, mdf)
}

func (s Service) SaveObject(ctx context.Context, bucket, fname string, md any) error {
func (s Service) saveObject(ctx context.Context, bucket, fname string, md any) error {
data, err := json.Marshal(md)
if err != nil {
return err
Expand Down
25 changes: 24 additions & 1 deletion client/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,39 @@ func (m *mockGCS) ListOjbect(ctx context.Context, bucketName, path string) ([]st
return args.Get(0).([]string), args.Error(1)
}

func (m *mockGCS) ExistsObject(ctx context.Context, bucketName, fileName string) (bool, error) {
args := m.Called(ctx, bucketName, fileName)
return args.Bool(0), args.Error(1)
}

func (s *serviceSuite) TestShouldWritePlainKeySuccessfully() {
name := "keyfile"
data := config.Metadata{Environment: "production"}
expData, err := json.Marshal(data)
s.gcs.On("ExistsObject", mock.AnythingOfType("*context.emptyCtx"), s.bucket, "dolores.md").Return(false, nil).Once()
s.gcs.On("WriteToObject", mock.AnythingOfType("*context.emptyCtx"), s.bucket, name, expData).Return(nil)
s.gcs.On("WriteToObject", mock.AnythingOfType("*context.emptyCtx"), s.bucket, "dolores.md", mock.AnythingOfType("[]uint8")).Return(nil).Once()
require.NoError(s.T(), err)

cfg := client.Configuration{}
err = s.Service.Init(s.ctx, s.bucket, cfg)

require.NoError(s.T(), err)
}

func (s *serviceSuite) TestShouldNotOverwriteMetadata() {
name := "dolores.md"
cfg := client.Configuration{
PublicKey: "public_key",
Metadata: config.Metadata{Location: "secrets"},
UserID: "test_user"}
s.gcs.On("ExistsObject", mock.AnythingOfType("*context.emptyCtx"), s.bucket, name).Return(true, nil).Once()
s.gcs.On("WriteToObject", mock.AnythingOfType("*context.emptyCtx"), s.bucket, "secrets/keys/test_user.key", []byte(cfg.PublicKey)).Return(nil).Once()

err = s.Service.SaveObject(s.ctx, s.bucket, name, data)
err := s.Service.Init(s.ctx, s.bucket, cfg)

require.NoError(s.T(), err)
s.gcs.AssertNotCalled(s.T(), "WriteToObject", "dolores.md", mock.Anything)
}

func TestGcsService(t *testing.T) {
Expand Down
15 changes: 3 additions & 12 deletions cmd/dolores/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,9 @@ func (c *InitCommand) initialize(ctx *cli.Context) error {
if err := d.SaveToDisk(); err != nil {
return fmt.Errorf("error saving dolores config: %w", err)
}

// saving metadata and append key to google cloud storage
storeCli := c.rcli(ctx.Context)
if publicKey != "" {
pubKey := fmt.Sprintf("%s/keys/%s.key", inp.Location, inp.UserID)
if err := storeCli.UploadPubKey(ctx.Context, inp.Bucket, pubKey, publicKey); err != nil {
return fmt.Errorf("error writing public key: %w", err)
}
}
// TODO: shouldn't overwrite metadata if it's already available in remote
if err := storeCli.SaveObject(ctx.Context, inp.Bucket, "dolores.md", md); err != nil {
c.log.Error().Msgf("error writing metadta: %v", err)
cli := c.rcli(ctx.Context)
cfg := client.Configuration{PublicKey: publicKey, Metadata: md, UserID: inp.UserID}
if err := cli.Init(ctx.Context, md.Bucket, cfg); err != nil {
return err
}
log.Info().Msgf("successfully initialized dolores")
Expand Down
33 changes: 26 additions & 7 deletions store/google/gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,9 @@ func (s StorageClient) WriteToObject(ctx context.Context, bucketName, fileName s
}

func (s StorageClient) ReadObject(ctx context.Context, bucketName, fileName string) ([]byte, error) {
bucket := s.Client.Bucket(bucketName)
if _, err := bucket.Attrs(ctx); err != nil {
return nil, fmt.Errorf("failed to get bucket: %w", err)
}
obj := bucket.Object(fileName)
if _, err := obj.Attrs(ctx); err != nil {
return nil, fmt.Errorf("failed to verify bucket attributes: %w", err)
obj, err := s.getObject(ctx, bucketName, fileName)
if err != nil {
return nil, err
}
rdr, err := obj.NewReader(ctx)
if err != nil {
Expand Down Expand Up @@ -114,6 +110,29 @@ func (s StorageClient) ListOjbect(ctx context.Context, bucketName, path string)
return objs, nil
}

func (s StorageClient) ExistsObject(ctx context.Context, bucket, fileName string) (bool, error) {
_, err := s.getObject(ctx, bucket, fileName)
if errors.Is(err, storage.ErrObjectNotExist) {
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}

func (s StorageClient) getObject(ctx context.Context, bucketName, fileName string) (*storage.ObjectHandle, error) {
bucket := s.Client.Bucket(bucketName)
if _, err := bucket.Attrs(ctx); err != nil {
return nil, fmt.Errorf("failed to get bucket: %w", err)
}
obj := bucket.Object(fileName)
if _, err := obj.Attrs(ctx); err != nil {
return nil, fmt.Errorf("failed to verify bucket attributes: %w", err)
}
return obj, nil
}

func (s StorageClient) createNewBucket(ctx context.Context, name string) error {
bucket := s.Client.Bucket(name)
attrs := &storage.BucketAttrs{PublicAccessPrevention: storage.PublicAccessPreventionEnforced}
Expand Down

0 comments on commit 77c7120

Please sign in to comment.