Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to aws-sdk-go-v2 #81

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 63 additions & 108 deletions cmd/internal/backup/providers/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@ package s3

import (
"context"
"errors"
"log/slog"
"path"
"path/filepath"
"strings"

"errors"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/metal-stack/backup-restore-sidecar/cmd/internal/backup/providers"
"github.com/metal-stack/backup-restore-sidecar/pkg/constants"
"github.com/spf13/afero"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

const (
Expand All @@ -29,8 +27,7 @@ const (
type BackupProviderS3 struct {
fs afero.Fs
log *slog.Logger
c *s3.S3
sess *session.Session
c *s3.Client
config *BackupProviderConfigS3
}

Expand All @@ -43,7 +40,7 @@ type BackupProviderConfigS3 struct {
SecretKey string
BackupName string
ObjectPrefix string
ObjectsToKeep int64
ObjectsToKeep int32
FS afero.Fs
}

Expand All @@ -65,123 +62,91 @@ func (c *BackupProviderConfigS3) validate() error {
}

// New returns a S3 backup provider
func New(log *slog.Logger, config *BackupProviderConfigS3) (*BackupProviderS3, error) {
if config == nil {
func New(log *slog.Logger, cfg *BackupProviderConfigS3) (*BackupProviderS3, error) {
if cfg == nil {
return nil, errors.New("s3 backup provider requires a provider config")
}

if config.ObjectsToKeep == 0 {
config.ObjectsToKeep = constants.DefaultObjectsToKeep
if cfg.ObjectsToKeep == 0 {
cfg.ObjectsToKeep = constants.DefaultObjectsToKeep
}
if config.BackupName == "" {
config.BackupName = defaultBackupName
if cfg.BackupName == "" {
cfg.BackupName = defaultBackupName
}
if config.FS == nil {
config.FS = afero.NewOsFs()
if cfg.FS == nil {
cfg.FS = afero.NewOsFs()
}

err := config.validate()
if err != nil {
return nil, err
}
s3Config := &aws.Config{
Credentials: credentials.NewStaticCredentials(config.AccessKey, config.SecretKey, ""),
Endpoint: aws.String(config.Endpoint),
Region: aws.String(config.Region),
S3ForcePathStyle: aws.Bool(true),
}
newSession, err := session.NewSession(s3Config)
err := cfg.validate()
if err != nil {
return nil, err
}
client := s3.New(newSession)

s3Cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(cfg.AccessKey, cfg.SecretKey, "")),
config.WithRegion(cfg.Region),
)
if err != nil {
return nil, err
}
client := s3.NewFromConfig(s3Cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String(cfg.Endpoint)
o.UsePathStyle = true
})

return &BackupProviderS3{
c: client,
sess: newSession,
config: config,
config: cfg,
log: log,
fs: config.FS,
fs: cfg.FS,
}, nil
}

// EnsureBackupBucket ensures a backup bucket at the backup provider
func (b *BackupProviderS3) EnsureBackupBucket(ctx context.Context) error {
bucket := aws.String(b.config.BucketName)

// create bucket
cparams := &s3.CreateBucketInput{
Bucket: bucket,
}

_, err := b.c.CreateBucketWithContext(ctx, cparams)
_, err := b.c.CreateBucket(ctx, &s3.CreateBucketInput{
Bucket: aws.String(b.config.BucketName),
})
if err != nil {
// FIXME check how to migrate to errors.As
//nolint
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case s3.ErrCodeBucketAlreadyExists:
case s3.ErrCodeBucketAlreadyOwnedByYou:
default:
return err
}
} else {
var bucketAlreadyExists *types.BucketAlreadyExists
var bucketAlreadyOwnerByYou *types.BucketAlreadyOwnedByYou
if !errors.As(err, &bucketAlreadyExists) && !errors.As(err, &bucketAlreadyOwnerByYou) {
return err
}
}

// enable versioning
versioning := &s3.PutBucketVersioningInput{
Bucket: bucket,
VersioningConfiguration: &s3.VersioningConfiguration{
Status: aws.String("Enabled"),
_, err = b.c.PutBucketVersioning(ctx, &s3.PutBucketVersioningInput{
Bucket: aws.String(b.config.BucketName),
VersioningConfiguration: &types.VersioningConfiguration{
Status: types.BucketVersioningStatusEnabled,
},
}
_, err = b.c.PutBucketVersioningWithContext(ctx, versioning)
})
if err != nil {
// FIXME check how to migrate to errors.As
//nolint
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
default:
return err
}
} else {
return err
}
return err
}

// add lifecyle policy
lifecycle := &s3.PutBucketLifecycleConfigurationInput{
Bucket: bucket,
LifecycleConfiguration: &s3.BucketLifecycleConfiguration{
Rules: []*s3.LifecycleRule{
_, err = b.c.PutBucketLifecycleConfiguration(ctx, &s3.PutBucketLifecycleConfigurationInput{
Bucket: aws.String(b.config.BucketName),
LifecycleConfiguration: &types.BucketLifecycleConfiguration{
Rules: []types.LifecycleRule{
{
NoncurrentVersionExpiration: &s3.NoncurrentVersionExpiration{
NoncurrentVersionExpiration: &types.NoncurrentVersionExpiration{
NoncurrentDays: &b.config.ObjectsToKeep,
},
Status: aws.String("Enabled"),
Status: types.ExpirationStatusEnabled,
ID: aws.String("backup-restore-lifecycle"),
Prefix: &b.config.ObjectPrefix,
Filter: &types.LifecycleRuleFilterMemberPrefix{
Value: b.config.ObjectPrefix,
},
},
},
},
}
_, err = b.c.PutBucketLifecycleConfigurationWithContext(ctx, lifecycle)
})
if err != nil {
// FIXME check how to migrate to errors.As
//nolint
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
default:
return err
}
} else {
return err
}
return err
}
return nil
}
Expand All @@ -194,8 +159,6 @@ func (b *BackupProviderS3) CleanupBackups(_ context.Context) error {

// DownloadBackup downloads the given backup version to the restoration folder
func (b *BackupProviderS3) DownloadBackup(ctx context.Context, version *providers.BackupVersion) error {
bucket := aws.String(b.config.BucketName)

downloadFileName := version.Name
if strings.Contains(downloadFileName, "/") {
downloadFileName = filepath.Base(downloadFileName)
Expand All @@ -209,16 +172,12 @@ func (b *BackupProviderS3) DownloadBackup(ctx context.Context, version *provider
}
defer f.Close()

downloader := s3manager.NewDownloader(b.sess)

_, err = downloader.DownloadWithContext(
ctx,
f,
&s3.GetObjectInput{
Bucket: bucket,
Key: &version.Name,
VersionId: &version.Version,
})
downloader := manager.NewDownloader(b.c)
_, err = downloader.Download(ctx, f, &s3.GetObjectInput{
Bucket: aws.String(b.config.BucketName),
Key: &version.Name,
VersionId: &version.Version,
})
if err != nil {
return err
}
Expand All @@ -228,8 +187,6 @@ func (b *BackupProviderS3) DownloadBackup(ctx context.Context, version *provider

// UploadBackup uploads a backup to the backup provider
func (b *BackupProviderS3) UploadBackup(ctx context.Context, sourcePath string) error {
bucket := aws.String(b.config.BucketName)

r, err := b.fs.Open(sourcePath)
if err != nil {
return err
Expand All @@ -243,9 +200,9 @@ func (b *BackupProviderS3) UploadBackup(ctx context.Context, sourcePath string)

b.log.Debug("uploading object", "src", sourcePath, "dest", destination)

uploader := s3manager.NewUploader(b.sess)
_, err = uploader.UploadWithContext(ctx, &s3manager.UploadInput{
Bucket: bucket,
uploader := manager.NewUploader(b.c)
_, err = uploader.Upload(ctx, &s3.PutObjectInput{
Bucket: aws.String(b.config.BucketName),
Key: aws.String(destination),
Body: r,
})
Expand All @@ -264,10 +221,8 @@ func (b *BackupProviderS3) GetNextBackupName(_ context.Context) string {

// ListBackups lists the available backups of the backup provider
func (b *BackupProviderS3) ListBackups(ctx context.Context) (providers.BackupVersions, error) {
bucket := aws.String(b.config.BucketName)

it, err := b.c.ListObjectVersionsWithContext(ctx, &s3.ListObjectVersionsInput{
Bucket: bucket,
it, err := b.c.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: aws.String(b.config.BucketName),
Prefix: &b.config.ObjectPrefix,
})
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions cmd/internal/backup/providers/s3/versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import (
"fmt"
"sort"

"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/metal-stack/backup-restore-sidecar/cmd/internal/backup/providers"
)

// BackupVersionsS3 contains the list of available backup versions
type BackupVersionsS3 struct {
objectAttrs []*s3.ObjectVersion
objectAttrs []types.ObjectVersion
}

// Latest returns latest backup version
Expand Down
2 changes: 1 addition & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ func initBackupProvider() error {
logger.WithGroup("backup"),
&s3.BackupProviderConfigS3{
ObjectPrefix: viper.GetString(objectPrefixFlg),
ObjectsToKeep: viper.GetInt64(objectsToKeepFlg),
ObjectsToKeep: viper.GetInt32(objectsToKeepFlg),
Region: viper.GetString(s3RegionFlg),
BucketName: viper.GetString(s3BucketNameFlg),
Endpoint: viper.GetString(s3EndpointFlg),
Expand Down
20 changes: 19 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ require (
cloud.google.com/go/storage v1.35.1
github.com/Masterminds/semver/v3 v3.2.1
github.com/avast/retry-go/v4 v4.5.1
github.com/aws/aws-sdk-go v1.45.7
github.com/aws/aws-sdk-go-v2 v1.25.3
github.com/aws/aws-sdk-go-v2/config v1.27.7
github.com/aws/aws-sdk-go-v2/credentials v1.17.7
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.9
github.com/aws/aws-sdk-go-v2/service/s3 v1.51.4
github.com/docker/docker v25.0.2+incompatible
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/lib/pq v1.10.9
Expand Down Expand Up @@ -46,6 +50,20 @@ require (
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 // indirect
github.com/aws/smithy-go v1.20.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
Expand Down
Loading
Loading