Skip to content

Commit

Permalink
migrate AWS Redshift services to AWS SDK v2
Browse files Browse the repository at this point in the history
  • Loading branch information
GavinFrazar committed Dec 28, 2024
1 parent 2bd71db commit 606a89a
Show file tree
Hide file tree
Showing 39 changed files with 923 additions and 469 deletions.
1 change: 1 addition & 0 deletions integrations/event-handler/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/kms v1.37.7 // indirect
github.com/aws/aws-sdk-go-v2/service/organizations v1.36.0 // indirect
github.com/aws/aws-sdk-go-v2/service/rds v1.92.0 // indirect
github.com/aws/aws-sdk-go-v2/service/redshift v1.53.0 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect
Expand Down
2 changes: 2 additions & 0 deletions integrations/event-handler/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,8 @@ github.com/aws/aws-sdk-go-v2/service/organizations v1.36.0 h1:CVHfN8ZVvWzDkAf/Qj
github.com/aws/aws-sdk-go-v2/service/organizations v1.36.0/go.mod h1:SVY+doFrL3KTvVMWzFLKvD7KYQ6GQfwNRPSQS7eA3cA=
github.com/aws/aws-sdk-go-v2/service/rds v1.92.0 h1:W0gUYAjO24u/M6tpR041wMHJWGzleOhxtCnNLImdrZs=
github.com/aws/aws-sdk-go-v2/service/rds v1.92.0/go.mod h1:ADD2uROOoEIXjbjDPEvDDZWnGmfKFYMddgKwG5RlBGw=
github.com/aws/aws-sdk-go-v2/service/redshift v1.53.0 h1:4/hmROBioc89sKlMVjHgOaH92zAkrAAMZR3BIvYwyD0=
github.com/aws/aws-sdk-go-v2/service/redshift v1.53.0/go.mod h1:UydVhUJOB/DaCJWiaBkPlvuzvWVcUlgbS2Bxn33bcKI=
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 h1:nyuzXooUNJexRT0Oy0UQY6AhOzxPxhtt4DcBIHyCnmw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0/go.mod h1:sT/iQz8JK3u/5gZkT+Hmr7GzVZehUMkRZpOaAwYXeGY=
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.1 h1:cfVjoEwOMOJOI6VoRQua0nI0KjZV9EAnR8bKaMeSppE=
Expand Down
1 change: 1 addition & 0 deletions integrations/terraform/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/kms v1.37.7 // indirect
github.com/aws/aws-sdk-go-v2/service/organizations v1.36.0 // indirect
github.com/aws/aws-sdk-go-v2/service/rds v1.92.0 // indirect
github.com/aws/aws-sdk-go-v2/service/redshift v1.53.0 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect
Expand Down
2 changes: 2 additions & 0 deletions integrations/terraform/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,8 @@ github.com/aws/aws-sdk-go-v2/service/organizations v1.36.0 h1:CVHfN8ZVvWzDkAf/Qj
github.com/aws/aws-sdk-go-v2/service/organizations v1.36.0/go.mod h1:SVY+doFrL3KTvVMWzFLKvD7KYQ6GQfwNRPSQS7eA3cA=
github.com/aws/aws-sdk-go-v2/service/rds v1.92.0 h1:W0gUYAjO24u/M6tpR041wMHJWGzleOhxtCnNLImdrZs=
github.com/aws/aws-sdk-go-v2/service/rds v1.92.0/go.mod h1:ADD2uROOoEIXjbjDPEvDDZWnGmfKFYMddgKwG5RlBGw=
github.com/aws/aws-sdk-go-v2/service/redshift v1.53.0 h1:4/hmROBioc89sKlMVjHgOaH92zAkrAAMZR3BIvYwyD0=
github.com/aws/aws-sdk-go-v2/service/redshift v1.53.0/go.mod h1:UydVhUJOB/DaCJWiaBkPlvuzvWVcUlgbS2Bxn33bcKI=
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 h1:nyuzXooUNJexRT0Oy0UQY6AhOzxPxhtt4DcBIHyCnmw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0/go.mod h1:sT/iQz8JK3u/5gZkT+Hmr7GzVZehUMkRZpOaAwYXeGY=
github.com/aws/aws-sdk-go-v2/service/sns v1.33.7 h1:N3o8mXK6/MP24BtD9sb51omEO9J9cgPM3Ughc293dZc=
Expand Down
4 changes: 2 additions & 2 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"

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/aws/aws-sdk-go/service/redshift"
"github.com/coreos/go-semver/semver"

"github.com/gravitational/teleport/lib/services"
Expand Down Expand Up @@ -244,7 +244,7 @@ func IsDBClusterAvailable(clusterStatus, clusterIndetifier *string) bool {
}

// IsRedshiftClusterAvailable checks if the Redshift cluster is available.
func IsRedshiftClusterAvailable(cluster *redshift.Cluster) bool {
func IsRedshiftClusterAvailable(cluster *redshifttypes.Cluster) bool {
// For a full list of status values, see:
// https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-clusters.html#rs-mgmt-cluster-status
//
Expand Down
15 changes: 12 additions & 3 deletions lib/cloud/aws/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,23 @@ import (
"github.com/gravitational/trace"
)

// ConvertRequestFailureError converts `error` into AWS RequestFailure errors
// to trace errors. If the provided error is not an `RequestFailure` it returns
// the error without modifying it.
// ConvertRequestFailureError converts `err` into AWS errors to trace errors.
// If the provided error is not a [awserr.RequestFailure] it delegates
// error conversion to [ConvertRequestFailureErrorV2] for SDK v2 compatibility.
// Prefer using [ConvertRequestFailureErrorV2] directly for AWS SDK v2 client
// errors.
func ConvertRequestFailureError(err error) error {
var requestErr awserr.RequestFailure
if errors.As(err, &requestErr) {
return convertRequestFailureErrorFromStatusCode(requestErr.StatusCode(), requestErr)
}
return ConvertRequestFailureErrorV2(err)
}

// ConvertRequestFailureErrorV2 converts AWS SDK v2 errors to trace errors.
// If the provided error is not a [awshttp.ResponseError] it returns the error
// without modifying it.
func ConvertRequestFailureErrorV2(err error) error {
var re *awshttp.ResponseError
if errors.As(err, &re) {
return convertRequestFailureErrorFromStatusCode(re.HTTPStatusCode(), re.Err)
Expand Down
8 changes: 4 additions & 4 deletions lib/cloud/aws/tags_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import (

ec2TypesV2 "github.com/aws/aws-sdk-go-v2/service/ec2/types"
rdsTypesV2 "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/redshift"
"github.com/aws/aws-sdk-go/service/redshiftserverless"
"github.com/aws/aws-sdk-go/service/secretsmanager"
"golang.org/x/exp/maps"
Expand All @@ -45,9 +45,9 @@ type ResourceTag interface {
// here and use a type switch for now.
rdsTypesV2.Tag |
ec2TypesV2.Tag |
redshifttypes.Tag |
*ec2.Tag |
*rds.Tag |
*redshift.Tag |
*elasticache.Tag |
*memorydb.Tag |
*redshiftserverless.Tag |
Expand Down Expand Up @@ -80,8 +80,6 @@ func resourceTagToKeyValue[Tag ResourceTag](tag Tag) (string, string) {
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *ec2.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *redshift.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *elasticache.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *memorydb.Tag:
Expand All @@ -92,6 +90,8 @@ func resourceTagToKeyValue[Tag ResourceTag](tag Tag) (string, string) {
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case ec2TypesV2.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case redshifttypes.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *opensearchservice.Tag:
return aws.StringValue(v.Key), aws.StringValue(v.Value)
case *secretsmanager.Tag:
Expand Down
45 changes: 45 additions & 0 deletions lib/cloud/awstesthelpers/tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package awstesthelpers

import (
"maps"
"slices"

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

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

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

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

return ret
}
23 changes: 0 additions & 23 deletions lib/cloud/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ import (
"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/redshift"
"github.com/aws/aws-sdk-go/service/redshift/redshiftiface"
"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 @@ -115,8 +113,6 @@ type AWSClients interface {
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)
// GetAWSRedshiftClient returns AWS Redshift client for the specified region.
GetAWSRedshiftClient(ctx context.Context, region string, opts ...AWSOptionsFn) (redshiftiface.RedshiftAPI, 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 @@ -517,15 +513,6 @@ func (c *cloudClients) GetAWSRDSClient(ctx context.Context, region string, opts
return rds.New(session), nil
}

// GetAWSRedshiftClient returns AWS Redshift client for the specified region.
func (c *cloudClients) GetAWSRedshiftClient(ctx context.Context, region string, opts ...AWSOptionsFn) (redshiftiface.RedshiftAPI, error) {
session, err := c.GetAWSSession(ctx, region, opts...)
if err != nil {
return nil, trace.Wrap(err)
}
return redshift.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 @@ -1033,7 +1020,6 @@ var _ Clients = (*TestCloudClients)(nil)
type TestCloudClients struct {
RDS rdsiface.RDSAPI
RDSPerRegion map[string]rdsiface.RDSAPI
Redshift redshiftiface.RedshiftAPI
RedshiftServerless redshiftserverlessiface.RedshiftServerlessAPI
ElastiCache elasticacheiface.ElastiCacheAPI
OpenSearch opensearchserviceiface.OpenSearchServiceAPI
Expand Down Expand Up @@ -1115,15 +1101,6 @@ func (c *TestCloudClients) GetAWSRDSClient(ctx context.Context, region string, o
return c.RDS, nil
}

// GetAWSRedshiftClient returns AWS Redshift client for the specified region.
func (c *TestCloudClients) GetAWSRedshiftClient(ctx context.Context, region string, opts ...AWSOptionsFn) (redshiftiface.RedshiftAPI, error) {
_, err := c.GetAWSSession(ctx, region, opts...)
if err != nil {
return nil, trace.Wrap(err)
}
return c.Redshift, 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
18 changes: 9 additions & 9 deletions lib/cloud/mocks/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ import (
"github.com/gravitational/trace"
)

// STSMock mocks AWS STS API.
type STSMock struct {
// STSClientV1 mocks AWS STS API for AWS SDK v1.
type STSClientV1 struct {
stsiface.STSAPI
ARN string
URL *url.URL
Expand All @@ -47,36 +47,36 @@ type STSMock struct {
mu sync.Mutex
}

func (m *STSMock) GetAssumedRoleARNs() []string {
func (m *STSClientV1) GetAssumedRoleARNs() []string {
m.mu.Lock()
defer m.mu.Unlock()
return m.assumedRoleARNs
}

func (m *STSMock) GetAssumedRoleExternalIDs() []string {
func (m *STSClientV1) GetAssumedRoleExternalIDs() []string {
m.mu.Lock()
defer m.mu.Unlock()
return m.assumedRoleExternalIDs
}

func (m *STSMock) ResetAssumeRoleHistory() {
func (m *STSClientV1) ResetAssumeRoleHistory() {
m.mu.Lock()
defer m.mu.Unlock()
m.assumedRoleARNs = nil
m.assumedRoleExternalIDs = nil
}

func (m *STSMock) GetCallerIdentityWithContext(aws.Context, *sts.GetCallerIdentityInput, ...request.Option) (*sts.GetCallerIdentityOutput, error) {
func (m *STSClientV1) GetCallerIdentityWithContext(aws.Context, *sts.GetCallerIdentityInput, ...request.Option) (*sts.GetCallerIdentityOutput, error) {
return &sts.GetCallerIdentityOutput{
Arn: aws.String(m.ARN),
}, nil
}

func (m *STSMock) AssumeRole(in *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
func (m *STSClientV1) AssumeRole(in *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
return m.AssumeRoleWithContext(context.Background(), in)
}

func (m *STSMock) AssumeRoleWithContext(ctx aws.Context, in *sts.AssumeRoleInput, _ ...request.Option) (*sts.AssumeRoleOutput, error) {
func (m *STSClientV1) AssumeRoleWithContext(ctx aws.Context, in *sts.AssumeRoleInput, _ ...request.Option) (*sts.AssumeRoleOutput, error) {
m.mu.Lock()
defer m.mu.Unlock()
if !slices.Contains(m.assumedRoleARNs, aws.StringValue(in.RoleArn)) {
Expand All @@ -94,7 +94,7 @@ func (m *STSMock) AssumeRoleWithContext(ctx aws.Context, in *sts.AssumeRoleInput
}, nil
}

func (m *STSMock) GetCallerIdentityRequest(req *sts.GetCallerIdentityInput) (*request.Request, *sts.GetCallerIdentityOutput) {
func (m *STSClientV1) GetCallerIdentityRequest(req *sts.GetCallerIdentityInput) (*request.Request, *sts.GetCallerIdentityOutput) {
return &request.Request{
HTTPRequest: &http.Request{
Header: http.Header{},
Expand Down
54 changes: 54 additions & 0 deletions lib/cloud/mocks/aws_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package mocks

import (
"context"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"

"github.com/gravitational/teleport/lib/cloud/awsconfig"
)

type AWSConfigProvider struct {
STSClient *STSClient
}

func (f *AWSConfigProvider) GetConfig(ctx context.Context, region string, optFns ...awsconfig.OptionsFn) (aws.Config, error) {
stsClt := f.STSClient
if stsClt == nil {
stsClt = &STSClient{}
}
optFns = append(optFns, awsconfig.WithAssumeRoleClientProviderFunc(func(cfg aws.Config) stscreds.AssumeRoleAPIClient {
if cfg.Credentials != nil {
if _, ok := cfg.Credentials.(*stscreds.AssumeRoleProvider); ok {
// Create a new fake client linked to the old one.
// Only do this for AssumeRoleProvider, to avoid attempting to
// load the real credential chain.
return &STSClient{
credentialProvider: cfg.Credentials,
root: stsClt,
}
}
}
return stsClt
}))
return awsconfig.GetConfig(ctx, region, optFns...)
}
Loading

0 comments on commit 606a89a

Please sign in to comment.