Skip to content

Commit

Permalink
migrate AWS RDS services to AWS SDK v2
Browse files Browse the repository at this point in the history
  • Loading branch information
GavinFrazar committed Jan 8, 2025
1 parent 5ed46a0 commit c8b7f0c
Show file tree
Hide file tree
Showing 42 changed files with 1,147 additions and 981 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ require (
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.15.23
github.com/aws/aws-sdk-go-v2/feature/dynamodbstreams/attributevalue v1.14.58
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.2
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.45
github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.34.3
github.com/aws/aws-sdk-go-v2/service/athena v1.49.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,8 @@ github.com/aws/aws-sdk-go-v2/feature/dynamodbstreams/attributevalue v1.14.58/go.
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.2 h1:fo+GuZNME9oGDc7VY+EBT+oCrco6RjRgUp1bKTcaHrU=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.2/go.mod h1:fnqb94UO6YCjBIic4WaqDYkNVAEFWOWiReVHitBBWW0=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.45 h1:ZxB8WFVYwolhDZxuZXoesHkl+L9cXLWy0K/G0QkNATc=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.45/go.mod h1:1krrbyoFFDqaNldmltPTP+mK3sAXLHPoaFtISOw2Hkk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw=
Expand Down
2 changes: 2 additions & 0 deletions integrations/terraform/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,8 @@ github.com/aws/aws-sdk-go-v2/feature/dynamodbstreams/attributevalue v1.14.58 h1:
github.com/aws/aws-sdk-go-v2/feature/dynamodbstreams/attributevalue v1.14.58/go.mod h1:1FDesv+tfF2w5mRnLQbB8P33BPfxrngXtfNcdnrtmjw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.2 h1:fo+GuZNME9oGDc7VY+EBT+oCrco6RjRgUp1bKTcaHrU=
github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.2/go.mod h1:fnqb94UO6YCjBIic4WaqDYkNVAEFWOWiReVHitBBWW0=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.45 h1:ZxB8WFVYwolhDZxuZXoesHkl+L9cXLWy0K/G0QkNATc=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.45/go.mod h1:1krrbyoFFDqaNldmltPTP+mK3sAXLHPoaFtISOw2Hkk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI=
Expand Down
51 changes: 42 additions & 9 deletions lib/cloud/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import (
"slices"
"strings"

rdstypes "github.com/aws/aws-sdk-go-v2/service/rds/types"
redshifttypes "github.com/aws/aws-sdk-go-v2/service/redshift/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elasticache"
"github.com/aws/aws-sdk-go/service/memorydb"
"github.com/aws/aws-sdk-go/service/opensearchservice"
"github.com/aws/aws-sdk-go/service/rds"
"github.com/coreos/go-semver/semver"

"github.com/gravitational/teleport/lib/services"
Expand Down Expand Up @@ -74,18 +74,51 @@ func IsOpenSearchDomainAvailable(domain *opensearchservice.DomainStatus) bool {
}

// IsRDSProxyAvailable checks if the RDS Proxy is available.
func IsRDSProxyAvailable(dbProxy *rds.DBProxy) bool {
return IsResourceAvailable(dbProxy, dbProxy.Status)
func IsRDSProxyAvailable(dbProxy *rdstypes.DBProxy) bool {
switch dbProxy.Status {
case
rdstypes.DBProxyStatusAvailable,
rdstypes.DBProxyStatusModifying,
rdstypes.DBProxyStatusReactivating:
return true
case
rdstypes.DBProxyStatusCreating,
rdstypes.DBProxyStatusDeleting,
rdstypes.DBProxyStatusIncompatibleNetwork,
rdstypes.DBProxyStatusInsufficientResourceLimits,
rdstypes.DBProxyStatusSuspended,
rdstypes.DBProxyStatusSuspending:
return false
}
slog.WarnContext(context.Background(), "Assuming RDS Proxy with unknown status is available",
"status", dbProxy.Status,
)
return true
}

// IsRDSProxyCustomEndpointAvailable checks if the RDS Proxy custom endpoint is available.
func IsRDSProxyCustomEndpointAvailable(customEndpoint *rds.DBProxyEndpoint) bool {
return IsResourceAvailable(customEndpoint, customEndpoint.Status)
func IsRDSProxyCustomEndpointAvailable(customEndpoint *rdstypes.DBProxyEndpoint) bool {
switch customEndpoint.Status {
case
rdstypes.DBProxyEndpointStatusAvailable,
rdstypes.DBProxyEndpointStatusModifying:
return true
case
rdstypes.DBProxyEndpointStatusCreating,
rdstypes.DBProxyEndpointStatusDeleting,
rdstypes.DBProxyEndpointStatusIncompatibleNetwork,
rdstypes.DBProxyEndpointStatusInsufficientResourceLimits:
return false
}
slog.WarnContext(context.Background(), "Assuming RDS Proxy custom endpoint with unknown status is available",
"status", customEndpoint.Status,
)
return true
}

// IsRDSInstanceSupported returns true if database supports IAM authentication.
// Currently, only MariaDB is being checked.
func IsRDSInstanceSupported(instance *rds.DBInstance) bool {
func IsRDSInstanceSupported(instance *rdstypes.DBInstance) bool {
// TODO(jakule): Check other engines.
if aws.StringValue(instance.Engine) != services.RDSEngineMariaDB {
return true
Expand All @@ -105,7 +138,7 @@ func IsRDSInstanceSupported(instance *rds.DBInstance) bool {
}

// IsRDSClusterSupported checks whether the Aurora cluster is supported.
func IsRDSClusterSupported(cluster *rds.DBCluster) bool {
func IsRDSClusterSupported(cluster *rdstypes.DBCluster) bool {
switch aws.StringValue(cluster.EngineMode) {
// Aurora Serverless v1 does NOT support IAM authentication.
// https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.html#aurora-serverless.limitations
Expand All @@ -129,7 +162,7 @@ func IsRDSClusterSupported(cluster *rds.DBCluster) bool {
}

// AuroraMySQLVersion extracts aurora mysql version from engine version
func AuroraMySQLVersion(cluster *rds.DBCluster) string {
func AuroraMySQLVersion(cluster *rdstypes.DBCluster) string {
// version guide: https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Updates.Versions.html
// a list of all the available versions: https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-engine-versions.html
//
Expand All @@ -154,7 +187,7 @@ func AuroraMySQLVersion(cluster *rds.DBCluster) string {
// for this DocumentDB cluster.
//
// https://docs.aws.amazon.com/documentdb/latest/developerguide/iam-identity-auth.html
func IsDocumentDBClusterSupported(cluster *rds.DBCluster) bool {
func IsDocumentDBClusterSupported(cluster *rdstypes.DBCluster) bool {
ver, err := semver.NewVersion(aws.StringValue(cluster.EngineVersion))
if err != nil {
slog.ErrorContext(context.Background(), "Failed to parse DocumentDB engine version", "version", aws.StringValue(cluster.EngineVersion))
Expand Down
29 changes: 3 additions & 26 deletions lib/cloud/aws/tags_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@ import (
"slices"

ec2TypesV2 "github.com/aws/aws-sdk-go-v2/service/ec2/types"
rdsTypesV2 "github.com/aws/aws-sdk-go-v2/service/rds/types"
rdstypes "github.com/aws/aws-sdk-go-v2/service/rds/types"
redshifttypes "github.com/aws/aws-sdk-go-v2/service/redshift/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/elasticache"
"github.com/aws/aws-sdk-go/service/memorydb"
"github.com/aws/aws-sdk-go/service/opensearchservice"
"github.com/aws/aws-sdk-go/service/rds"
"github.com/aws/aws-sdk-go/service/redshiftserverless"
"github.com/aws/aws-sdk-go/service/secretsmanager"
"golang.org/x/exp/maps"
Expand All @@ -43,11 +42,10 @@ import (
type ResourceTag interface {
// TODO Go generic does not allow access common fields yet. List all types
// here and use a type switch for now.
rdsTypesV2.Tag |
rdstypes.Tag |
ec2TypesV2.Tag |
redshifttypes.Tag |
*ec2.Tag |
*rds.Tag |
*elasticache.Tag |
*memorydb.Tag |
*redshiftserverless.Tag |
Expand Down Expand Up @@ -76,8 +74,6 @@ func TagsToLabels[Tag ResourceTag](tags []Tag) map[string]string {

func resourceTagToKeyValue[Tag ResourceTag](tag Tag) (string, string) {
switch v := any(tag).(type) {
case *rds.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *ec2.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *elasticache.Tag:
Expand All @@ -86,7 +82,7 @@ func resourceTagToKeyValue[Tag ResourceTag](tag Tag) (string, string) {
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *redshiftserverless.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case rdsTypesV2.Tag:
case rdstypes.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case ec2TypesV2.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
Expand Down Expand Up @@ -123,22 +119,3 @@ func LabelsToTags[T any, PT SettableTag[T]](labels map[string]string) (tags []*T
}
return
}

// LabelsToRDSV2Tags converts labels into [rdsTypesV2.Tag] list.
func LabelsToRDSV2Tags(labels map[string]string) []rdsTypesV2.Tag {
keys := maps.Keys(labels)
slices.Sort(keys)

ret := make([]rdsTypesV2.Tag, 0, len(keys))
for _, key := range keys {
key := key
value := labels[key]

ret = append(ret, rdsTypesV2.Tag{
Key: &key,
Value: &value,
})
}

return ret
}
25 changes: 2 additions & 23 deletions lib/cloud/aws/tags_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ import (
"testing"

rdsTypesV2 "github.com/aws/aws-sdk-go-v2/service/rds/types"
rdstypes "github.com/aws/aws-sdk-go-v2/service/rds/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/elasticache"
"github.com/aws/aws-sdk-go/service/rds"
"github.com/stretchr/testify/require"
)

func TestTagsToLabels(t *testing.T) {
t.Parallel()

t.Run("rds", func(t *testing.T) {
inputTags := []*rds.Tag{
inputTags := []rdstypes.Tag{
{
Key: aws.String("Env"),
Value: aws.String("dev"),
Expand Down Expand Up @@ -135,25 +135,4 @@ func TestLabelsToTags(t *testing.T) {
actualTags := LabelsToTags[elasticache.Tag](inputLabels)
require.Equal(t, expectTags, actualTags)
})

t.Run("rdsV2", func(t *testing.T) {
inputLabels := map[string]string{
"labelB": "valueB",
"labelA": "valueA",
}

expectTags := []rdsTypesV2.Tag{
{
Key: aws.String("labelA"),
Value: aws.String("valueA"),
},
{
Key: aws.String("labelB"),
Value: aws.String("valueB"),
},
}

actualTags := LabelsToRDSV2Tags(inputLabels)
require.EqualValues(t, expectTags, actualTags)
})
}
20 changes: 20 additions & 0 deletions lib/cloud/awstesthelpers/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"maps"
"slices"

rdstypes "github.com/aws/aws-sdk-go-v2/service/rds/types"
redshifttypes "github.com/aws/aws-sdk-go-v2/service/redshift/types"
)

Expand All @@ -43,3 +44,22 @@ func LabelsToRedshiftTags(labels map[string]string) []redshifttypes.Tag {

return ret
}

// LabelsToRDSTags converts labels into a [rdstypes.Tag] list.
func LabelsToRDSTags(labels map[string]string) []rdstypes.Tag {
keys := slices.Collect(maps.Keys(labels))
slices.Sort(keys)

ret := make([]rdstypes.Tag, 0, len(keys))
for _, key := range keys {
key := key
value := labels[key]

ret = append(ret, rdstypes.Tag{
Key: &key,
Value: &value,
})
}

return ret
}
27 changes: 0 additions & 27 deletions lib/cloud/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ import (
"github.com/aws/aws-sdk-go/service/memorydb/memorydbiface"
"github.com/aws/aws-sdk-go/service/opensearchservice"
"github.com/aws/aws-sdk-go/service/opensearchservice/opensearchserviceiface"
"github.com/aws/aws-sdk-go/service/rds"
"github.com/aws/aws-sdk-go/service/rds/rdsiface"
"github.com/aws/aws-sdk-go/service/redshiftserverless"
"github.com/aws/aws-sdk-go/service/redshiftserverless/redshiftserverlessiface"
"github.com/aws/aws-sdk-go/service/s3"
Expand Down Expand Up @@ -111,8 +109,6 @@ type GCPClients interface {
type AWSClients interface {
// GetAWSSession returns AWS session for the specified region and any role(s).
GetAWSSession(ctx context.Context, region string, opts ...AWSOptionsFn) (*awssession.Session, error)
// GetAWSRDSClient returns AWS RDS client for the specified region.
GetAWSRDSClient(ctx context.Context, region string, opts ...AWSOptionsFn) (rdsiface.RDSAPI, error)
// GetAWSRedshiftServerlessClient returns AWS Redshift Serverless client for the specified region.
GetAWSRedshiftServerlessClient(ctx context.Context, region string, opts ...AWSOptionsFn) (redshiftserverlessiface.RedshiftServerlessAPI, error)
// GetAWSElastiCacheClient returns AWS ElastiCache client for the specified region.
Expand Down Expand Up @@ -504,15 +500,6 @@ func (c *cloudClients) GetAWSSession(ctx context.Context, region string, opts ..
return c.getAWSSessionForRole(ctx, region, options)
}

// GetAWSRDSClient returns AWS RDS client for the specified region.
func (c *cloudClients) GetAWSRDSClient(ctx context.Context, region string, opts ...AWSOptionsFn) (rdsiface.RDSAPI, error) {
session, err := c.GetAWSSession(ctx, region, opts...)
if err != nil {
return nil, trace.Wrap(err)
}
return rds.New(session), nil
}

// GetAWSRedshiftServerlessClient returns AWS Redshift Serverless client for the specified region.
func (c *cloudClients) GetAWSRedshiftServerlessClient(ctx context.Context, region string, opts ...AWSOptionsFn) (redshiftserverlessiface.RedshiftServerlessAPI, error) {
session, err := c.GetAWSSession(ctx, region, opts...)
Expand Down Expand Up @@ -1018,8 +1005,6 @@ var _ Clients = (*TestCloudClients)(nil)

// TestCloudClients are used in tests.
type TestCloudClients struct {
RDS rdsiface.RDSAPI
RDSPerRegion map[string]rdsiface.RDSAPI
RedshiftServerless redshiftserverlessiface.RedshiftServerlessAPI
ElastiCache elasticacheiface.ElastiCacheAPI
OpenSearch opensearchserviceiface.OpenSearchServiceAPI
Expand Down Expand Up @@ -1089,18 +1074,6 @@ func (c *TestCloudClients) getAWSSessionForRegion(region string) (*awssession.Se
})
}

// GetAWSRDSClient returns AWS RDS client for the specified region.
func (c *TestCloudClients) GetAWSRDSClient(ctx context.Context, region string, opts ...AWSOptionsFn) (rdsiface.RDSAPI, error) {
_, err := c.GetAWSSession(ctx, region, opts...)
if err != nil {
return nil, trace.Wrap(err)
}
if len(c.RDSPerRegion) != 0 {
return c.RDSPerRegion[region], nil
}
return c.RDS, nil
}

// GetAWSRedshiftServerlessClient returns AWS Redshift Serverless client for the specified region.
func (c *TestCloudClients) GetAWSRedshiftServerlessClient(ctx context.Context, region string, opts ...AWSOptionsFn) (redshiftserverlessiface.RedshiftServerlessAPI, error) {
_, err := c.GetAWSSession(ctx, region, opts...)
Expand Down
5 changes: 5 additions & 0 deletions lib/cloud/mocks/aws_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ import (
)

type AWSConfigProvider struct {
Err error
STSClient *STSClient
OIDCIntegrationClient awsconfig.OIDCIntegrationClient
}

func (f *AWSConfigProvider) GetConfig(ctx context.Context, region string, optFns ...awsconfig.OptionsFn) (aws.Config, error) {
if f.Err != nil {
return aws.Config{}, f.Err
}

stsClt := f.STSClient
if stsClt == nil {
stsClt = &STSClient{}
Expand Down
Loading

0 comments on commit c8b7f0c

Please sign in to comment.