Skip to content

Commit 83a1b4b

Browse files
authored
feat(dsql-cluster): add DSQL Cluster resource (#9)
2 parents 7a55789 + ab7847c commit 83a1b4b

File tree

3 files changed

+178
-3
lines changed

3 files changed

+178
-3
lines changed

go.mod

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ toolchain go1.24.0
66

77
require (
88
github.com/aws/aws-sdk-go v1.55.6
9-
github.com/aws/aws-sdk-go-v2 v1.36.2
9+
github.com/aws/aws-sdk-go-v2 v1.36.3
1010
github.com/aws/aws-sdk-go-v2/config v1.28.11
1111
github.com/aws/aws-sdk-go-v2/credentials v1.17.60
1212
github.com/aws/aws-sdk-go-v2/service/apigateway v1.28.12
1313
github.com/aws/aws-sdk-go-v2/service/appsync v1.42.3
1414
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.11
15+
github.com/aws/aws-sdk-go-v2/service/dsql v1.1.1
1516
github.com/aws/aws-sdk-go-v2/service/iam v1.38.10
1617
github.com/aws/aws-sdk-go-v2/service/route53profiles v1.4.16
1718
github.com/aws/aws-sdk-go-v2/service/s3 v1.72.3
@@ -38,8 +39,8 @@ require (
3839
require (
3940
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
4041
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29 // indirect
41-
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 // indirect
42-
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 // indirect
42+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
43+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
4344
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
4445
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.27 // indirect
4546
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ github.com/aws/aws-sdk-go-v2 v1.36.1 h1:iTDl5U6oAhkNPba0e1t1hrwAo02ZMqbrGq4k5JBW
44
github.com/aws/aws-sdk-go-v2 v1.36.1/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM=
55
github.com/aws/aws-sdk-go-v2 v1.36.2 h1:Ub6I4lq/71+tPb/atswvToaLGVMxKZvjYDVOWEExOcU=
66
github.com/aws/aws-sdk-go-v2 v1.36.2/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
7+
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
8+
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
79
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8=
810
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc=
911
github.com/aws/aws-sdk-go-v2/config v1.28.11 h1:7Ekru0IkRHRnSRWGQLnLN6i0o1Jncd0rHo2T130+tEQ=
@@ -24,10 +26,14 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 h1:BjUcr3X3K0wZPGFg2
2426
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32/go.mod h1:80+OGC/bgzzFFTUmcuwD0lb4YutwQeKLFpmt6hoWapU=
2527
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 h1:knLyPMw3r3JsU8MFHWctE4/e2qWbPaxDYLlohPvnY8c=
2628
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33/go.mod h1:EBp2HQ3f+XCB+5J+IoEbGhoV7CpJbnrsd4asNXmTL0A=
29+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
30+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
2731
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 h1:m1GeXHVMJsRsUAqG6HjZWx9dj7F5TR+cF1bjyfYyBd4=
2832
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32/go.mod h1:IitoQxGfaKdVLNg0hD8/DXmAqNy0H4K2H2Sf91ti8sI=
2933
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 h1:K0+Ne08zqti8J9jwENxZ5NoUyBnaFDTu3apwQJWrwwA=
3034
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33/go.mod h1:K97stwwzaWzmqxO8yLGHhClbVW1tC6VT1pDLk1pGrq4=
35+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
36+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
3137
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
3238
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
3339
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.27 h1:AmB5QxnD+fBFrg9LcqzkgF/CaYvMyU/BTlejG4t1S7Q=
@@ -48,6 +54,8 @@ github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10 h1:fdLh7eMf5mxtggx2nG0+
4854
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10/go.mod h1:uBca+/1aH5v/RYWXqyymLrsbmx1vU9bBxeurlC627Gc=
4955
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.11 h1:azwNdO35Sp6EtX1RTi+gjrdng88tb2LUA7arvoWO3TI=
5056
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.11/go.mod h1:nr2/4ch+huedh56oGZClTeCVENvMBqeEkzkObAFCDQM=
57+
github.com/aws/aws-sdk-go-v2/service/dsql v1.1.1 h1:h2YbGqsnzL36l2B/Bd/dvrHfrKo/b7HVpZykL3yIQn8=
58+
github.com/aws/aws-sdk-go-v2/service/dsql v1.1.1/go.mod h1:StDU/D7R42LhrKp24PGzvxyKjjDm0lwo9JMwuy2qbo4=
5159
github.com/aws/aws-sdk-go-v2/service/iam v1.38.10 h1:u/MwkFwRkKRDvy7D76/khJTk8HMp4mC5sZKErU53jos=
5260
github.com/aws/aws-sdk-go-v2/service/iam v1.38.10/go.mod h1:Gid0WEVky3EWbkeXiS67kHhbiK+q3/wO/hvPh7plR0c=
5361
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA=

resources/dsql-cluster.go

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package resources
2+
3+
import (
4+
"context"
5+
"errors"
6+
"slices"
7+
"time"
8+
9+
"github.com/gotidy/ptr"
10+
11+
"github.com/aws/aws-sdk-go-v2/service/dsql"
12+
dsqltypes "github.com/aws/aws-sdk-go-v2/service/dsql/types"
13+
14+
"github.com/ekristen/libnuke/pkg/registry"
15+
"github.com/ekristen/libnuke/pkg/resource"
16+
libsettings "github.com/ekristen/libnuke/pkg/settings"
17+
"github.com/ekristen/libnuke/pkg/types"
18+
19+
"github.com/ekristen/aws-nuke/v3/pkg/nuke"
20+
)
21+
22+
const DSQLClusterResource = "DSQLCluster"
23+
24+
func init() {
25+
registry.Register(&registry.Registration{
26+
Name: DSQLClusterResource,
27+
Scope: nuke.Account,
28+
Resource: &DSQLCluster{},
29+
Lister: &DSQLClusterLister{},
30+
Settings: []string{
31+
"DisableDeletionProtection",
32+
},
33+
})
34+
}
35+
36+
type DSQLClusterLister struct{}
37+
38+
func (l *DSQLClusterLister) List(ctx context.Context, o interface{}) ([]resource.Resource, error) {
39+
opts := o.(*nuke.ListerOpts)
40+
svc := dsql.NewFromConfig(*opts.Config)
41+
var resources []resource.Resource
42+
43+
if !l.IsSupportedRegion(opts.Region.Name) {
44+
return resources, nil
45+
}
46+
47+
params := &dsql.ListClustersInput{
48+
MaxResults: ptr.Int32(100),
49+
}
50+
51+
for {
52+
res, err := svc.ListClusters(ctx, params)
53+
if err != nil {
54+
return nil, err
55+
}
56+
57+
for _, clusterSummary := range res.Clusters {
58+
// get additional cluster metadata not returned in ListClusters
59+
cluster, err := svc.GetCluster(ctx, &dsql.GetClusterInput{
60+
Identifier: clusterSummary.Identifier,
61+
})
62+
if err != nil {
63+
return nil, err
64+
}
65+
// get cluster tags
66+
var tags map[string]string
67+
tagsRes, err := svc.ListTagsForResource(ctx, &dsql.ListTagsForResourceInput{
68+
ResourceArn: clusterSummary.Arn,
69+
})
70+
if err != nil {
71+
opts.Logger.Warnf("unable to fetch tags for dsql cluster: %s", ptr.ToString(clusterSummary.Arn))
72+
} else {
73+
tags = tagsRes.Tags
74+
}
75+
76+
resources = append(resources, &DSQLCluster{
77+
svc: svc,
78+
Arn: clusterSummary.Arn,
79+
CreationTime: cluster.CreationTime,
80+
DeletionProtectionEnabled: cluster.DeletionProtectionEnabled,
81+
Identifier: clusterSummary.Identifier,
82+
Status: cluster.Status,
83+
Tags: tags,
84+
})
85+
}
86+
87+
if res.NextToken == nil {
88+
break
89+
}
90+
91+
params.NextToken = res.NextToken
92+
}
93+
94+
return resources, nil
95+
}
96+
97+
func (l *DSQLClusterLister) IsSupportedRegion(region string) bool {
98+
// https://aws.amazon.com/rds/aurora/dsql/faqs/#:~:text=available%20in%20all-,AWS%20Regions,-%3F
99+
// NOTE: us-west-2 (Oregon) is available as a witness region, but clusters cannot be created in this region
100+
supportedRegions := []string{
101+
"us-east-1",
102+
"us-east-2",
103+
}
104+
105+
return slices.Contains(supportedRegions, region)
106+
}
107+
108+
type DSQLCluster struct {
109+
svc *dsql.Client
110+
settings *libsettings.Setting
111+
Arn *string
112+
CreationTime *time.Time
113+
DeletionProtectionEnabled *bool
114+
Identifier *string
115+
Status dsqltypes.ClusterStatus
116+
Tags map[string]string
117+
}
118+
119+
func (r *DSQLCluster) Remove(ctx context.Context) error {
120+
err := r.RemoveDeletionProtection(ctx)
121+
if err != nil {
122+
return err
123+
}
124+
125+
_, err = r.svc.DeleteCluster(ctx, &dsql.DeleteClusterInput{
126+
Identifier: r.Identifier,
127+
})
128+
129+
return err
130+
}
131+
132+
func (r *DSQLCluster) Filter() error {
133+
if r.Status == dsqltypes.ClusterStatusDeleted {
134+
return errors.New("dsql cluster already deleted")
135+
}
136+
137+
return nil
138+
}
139+
140+
func (r *DSQLCluster) RemoveDeletionProtection(ctx context.Context) error {
141+
if !r.settings.GetBool("DisableDeletionProtection") {
142+
return nil
143+
}
144+
145+
_, err := r.svc.UpdateCluster(ctx, &dsql.UpdateClusterInput{
146+
Identifier: r.Identifier,
147+
DeletionProtectionEnabled: ptr.Bool(false),
148+
})
149+
if err != nil {
150+
return err
151+
}
152+
153+
return nil
154+
}
155+
156+
func (r *DSQLCluster) Settings(settings *libsettings.Setting) {
157+
r.settings = settings
158+
}
159+
160+
func (r *DSQLCluster) Properties() types.Properties {
161+
return types.NewPropertiesFromStruct(r)
162+
}
163+
164+
func (r *DSQLCluster) String() string {
165+
return *r.Arn
166+
}

0 commit comments

Comments
 (0)