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 AWS RDS services to AWS SDK v2 #50848

Merged
merged 1 commit into from
Jan 10, 2025
Merged
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -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=
2 changes: 2 additions & 0 deletions integrations/terraform/go.sum
Original file line number Diff line number Diff line change
@@ -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=
51 changes: 42 additions & 9 deletions lib/cloud/aws/aws.go
Original file line number Diff line number Diff line change
@@ -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"
@@ -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
@@ -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
@@ -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
//
@@ -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))
29 changes: 3 additions & 26 deletions lib/cloud/aws/tags_helpers.go
Original file line number Diff line number Diff line change
@@ -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"
@@ -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 |
@@ -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:
@@ -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)
@@ -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
@@ -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"),
@@ -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
@@ -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"
)

@@ -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
@@ -49,8 +49,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"
@@ -109,8 +107,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.
@@ -500,15 +496,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...)
@@ -1005,8 +992,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
@@ -1075,18 +1060,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...)
5 changes: 5 additions & 0 deletions lib/cloud/mocks/aws_config.go
Original file line number Diff line number Diff line change
@@ -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{}
Loading