Skip to content

Commit 8d5a91f

Browse files
committed
refactor: migrate AWS resources to generic Resource[C] pattern
This refactoring introduces a type-safe generic resource pattern that simplifies AWS resource implementations and reduces code duplication. Key changes: - Introduce Resource[C] generic type with type-safe client handling - Add WrapAwsInitClient helper for AWS config initialization - Add batch deleters: SimpleBatchDeleter, SequentialDeleter, BulkDeleter, MultiStepDeleter, DeleteThenWait - Merge all *_types.go files into main resource files (55 files deleted) - Remove base_resource.go, common.go, globals.go (consolidated into adapter.go) - Update golangci-lint config for v2 compatibility - Fix context key type for SA1029 compliance - Add pagination support across all resources Net reduction: ~5,500 lines of code across 280 files changed.
1 parent c450ebc commit 8d5a91f

File tree

317 files changed

+15603
-22602
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

317 files changed

+15603
-22602
lines changed

.golangci.yml

Lines changed: 38 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
version: "2"
2+
13
run:
24
timeout: 10m
35
tests: true
@@ -6,85 +8,68 @@ run:
68

79
linters:
810
enable:
9-
# Default linters (these come with golangci-lint)
10-
- errcheck # Checking for unchecked errors - critical for nil safety
11-
- gosimple # Simplify code
12-
- govet # Reports suspicious constructs including nil issues
13-
- ineffassign # Detects when assignments to existing variables are not used
14-
- staticcheck # Comprehensive static analysis including nil checks (SA5011)
15-
- typecheck # Like the front-end of a Go compiler, parses and type-checks
16-
- unused # Checks for unused constants, variables, functions and types
17-
18-
# Critical nil safety linters
19-
- nilnil # Checks that there is no simultaneous return of nil error and an invalid value
20-
- nilerr # Finds the code that returns nil even if it checks that the error is not nil
21-
11+
# Default linters
12+
- errcheck # Checking for unchecked errors
13+
- govet # Reports suspicious constructs
14+
- ineffassign # Detects unused assignments
15+
- staticcheck # Comprehensive static analysis
16+
- unused # Checks for unused code
17+
2218
# Code quality linters
23-
- bodyclose # Checks whether HTTP response body is closed successfully
24-
- durationcheck # Check for two common problems with time.Duration
25-
- errorlint # Find code that will cause problems with error handling
26-
- copyloopvar # Checks for pointers to enclosing loop variables (replaces exportloopref)
27-
- noctx # Finds sending http request without context.Context
28-
19+
- bodyclose # Checks HTTP response body is closed
20+
- durationcheck # Check time.Duration issues
21+
- errorlint # Error handling problems
22+
- copyloopvar # Checks loop variable captures
23+
- noctx # HTTP requests without context
24+
- nilerr # Returns nil even when error is not nil
25+
2926
# Style linters
30-
- gofmt # Checks whether code was gofmt-ed
31-
- goimports # Check import statements are formatted
32-
- misspell # Finds commonly misspelled English words in comments
33-
- whitespace # Detection of leading and trailing whitespace
27+
- misspell # Finds misspelled words
28+
- whitespace # Leading/trailing whitespace
3429

3530
disable:
36-
- depguard # Too restrictive for dependencies
37-
- exhaustive # Too strict for switch statements
38-
- gochecknoglobals # We use some globals
39-
- lll # Line length limit is too strict
40-
- wsl # Whitespace linter is too opinionated
31+
- depguard
32+
- exhaustive
33+
- gochecknoglobals
34+
- lll
35+
- wsl
36+
37+
formatters:
38+
enable:
39+
- gofmt
40+
- goimports
4141

4242
linters-settings:
4343
errcheck:
4444
check-type-assertions: true
4545
check-blank: true
46-
46+
4747
govet:
4848
enable:
49-
- shadow # Check for shadowed variables
50-
49+
- shadow
50+
5151
staticcheck:
52-
checks: ["all", "-ST1000", "-ST1003"] # Disable some stylistic checks
53-
54-
nilnil:
55-
checked-types:
56-
- ptr
57-
- func
58-
- iface
59-
- map
60-
- chan
52+
checks: ["all", "-ST1000", "-ST1003", "-QF1008", "-SA1029", "-SA9003"]
6153

6254
issues:
63-
# Only show issues on new/changed lines
64-
# This makes adoption easier for existing codebases
6555
new: true
66-
67-
# Exclude directories from all linters
56+
6857
exclude-dirs:
6958
- vendor
7059
- third_party
7160
- generated
72-
61+
7362
exclude-rules:
74-
# Exclude test files from some linters
7563
- path: _test\.go
7664
linters:
7765
- errcheck
7866
- noctx
79-
80-
# Exclude generated files
67+
- staticcheck
68+
8169
- path: "generated"
8270
linters:
8371
- staticcheck
8472
- govet
85-
86-
# Maximum issues count per one linter
73+
8774
max-issues-per-linter: 0
88-
89-
# Maximum count of issues with the same text
90-
max-same-issues: 0
75+
max-same-issues: 0

aws/resource_registry.go

Lines changed: 101 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,29 @@ func GetAndInitRegisteredResources(session aws.Config, region string) []*AwsReso
3131
}
3232

3333
// GetRegisteredGlobalResources - returns a list of registered global resources.
34+
// Note: The order is important for IAM resources due to dependencies:
35+
// 1. Users (removes itself from groups, detaches its policies)
36+
// 2. Groups (removes remaining users, detaches its policies)
37+
// 3. Roles (deletes instance profiles, detaches policies)
38+
// 4. Service Linked Roles (special AWS-managed roles)
39+
// 5. Instance Profiles (any remaining standalone profiles)
40+
// 6. Policies (now fully detached from all entities)
3441
func getRegisteredGlobalResources() []AwsResource {
3542
return []AwsResource{
36-
&resources.DBGlobalClusters{},
37-
&resources.IAMUsers{},
38-
&resources.IAMGroups{},
39-
&resources.IAMPolicies{},
40-
&resources.IAMInstanceProfiles{},
41-
&resources.IAMRoles{},
42-
&resources.IAMServiceLinkedRoles{},
43-
&resources.OIDCProviders{},
44-
&resources.Route53HostedZone{},
45-
&resources.Route53CidrCollection{},
46-
&resources.Route53TrafficPolicy{},
43+
resources.NewCloudfrontDistributions(),
44+
resources.NewDBGlobalClusters(),
45+
// IAM deletion order: Users -> Groups -> Roles -> ServiceLinkedRoles -> InstanceProfiles -> Policies
46+
resources.NewIAMUsers(),
47+
resources.NewIAMGroups(),
48+
resources.NewIAMRoles(),
49+
resources.NewIAMServiceLinkedRoles(),
50+
resources.NewIAMInstanceProfiles(),
51+
resources.NewIAMPolicies(),
52+
resources.NewOIDCProviders(),
53+
resources.NewRoute53HostedZone(),
54+
resources.NewRoute53CidrCollections(),
55+
resources.NewRoute53TrafficPolicies(),
56+
resources.NewS3Buckets(),
4757
}
4858
}
4959

@@ -56,117 +66,123 @@ func getRegisteredRegionalResources() []AwsResource {
5666
resources.NewACM(),
5767
resources.NewACMPCA(),
5868
resources.NewAMIs(),
59-
&resources.ApiGateway{},
60-
&resources.ApiGatewayV2{},
61-
&resources.ASGroups{},
69+
resources.NewApiGateway(),
70+
resources.NewApiGatewayV2(),
71+
resources.NewASGroups(),
6272
resources.NewAppRunnerService(),
6373
resources.NewBackupVault(),
6474
resources.NewManagedPrometheus(),
6575
resources.NewGrafana(),
6676
resources.NewEventBridgeSchedule(),
67-
&resources.EventBridgeScheduleGroup{},
77+
resources.NewEventBridgeScheduleGroup(),
6878
resources.NewEventBridgeArchive(),
69-
&resources.EventBridgeRule{},
70-
&resources.EventBridge{},
79+
resources.NewEventBridgeRule(),
80+
resources.NewEventBridge(),
7181
resources.NewCloudtrailTrail(),
72-
&resources.CloudFormationStacks{},
82+
resources.NewCloudFormationStacks(),
7383
resources.NewCloudWatchAlarms(),
7484
resources.NewCloudWatchDashboards(),
7585
resources.NewCloudWatchLogGroups(),
76-
&resources.CloudMapServices{},
77-
&resources.CloudMapNamespaces{},
78-
&resources.CodeDeployApplications{},
86+
resources.NewCloudMapServices(),
87+
resources.NewCloudMapNamespaces(),
88+
resources.NewCodeDeployApplications(),
7989
resources.NewConfigServiceRecorders(),
80-
&resources.ConfigServiceRule{},
90+
resources.NewConfigServiceRules(),
8191
resources.NewDataSyncTask(),
8292
resources.NewDataSyncLocation(),
8393
resources.NewDynamoDB(),
84-
&resources.EBSVolumes{},
94+
resources.NewEBSVolumes(),
8595
resources.NewEBApplications(),
86-
&resources.EC2Instances{},
87-
&resources.EC2DedicatedHosts{},
96+
resources.NewEC2Instances(),
97+
resources.NewEC2DedicatedHosts(),
8898
resources.NewEC2KeyPairs(),
8999
resources.NewEC2PlacementGroups(),
90-
&resources.TransitGateways{},
100+
resources.NewTransitGateways(),
91101
resources.NewTransitGatewaysRouteTables(),
92102
// Note: nuking transitgateway vpc attachement before nuking the vpc since vpc could be associated with it.
93103
resources.NewTransitGatewayPeeringAttachment(),
94-
&resources.TransitGatewaysVpcAttachment{},
95-
&resources.EC2Endpoints{},
104+
resources.NewTransitGatewaysVpcAttachment(),
105+
resources.NewEC2Endpoints(),
96106
resources.NewECR(),
97-
&resources.ECSClusters{},
98-
&resources.ECSServices{},
99-
&resources.EgressOnlyInternetGateway{},
100-
&resources.ElasticFileSystem{},
107+
resources.NewECSClusters(),
108+
resources.NewECSServices(),
109+
resources.NewEgressOnlyInternetGateway(),
110+
resources.NewElasticFileSystem(),
101111
resources.NewEIPAddresses(),
102-
&resources.EKSClusters{},
103-
&resources.ElasticCacheServerless{},
104-
&resources.Elasticaches{},
105-
&resources.ElasticacheParameterGroups{},
106-
&resources.ElasticacheSubnetGroups{},
107-
&resources.LoadBalancers{},
108-
&resources.LoadBalancersV2{},
112+
resources.NewEKSClusters(),
113+
resources.NewElasticCacheServerless(),
114+
resources.NewElasticaches(),
115+
resources.NewElasticacheParameterGroups(),
116+
resources.NewElasticacheSubnetGroups(),
117+
resources.NewLoadBalancers(),
118+
resources.NewLoadBalancersV2(),
109119
resources.NewGuardDuty(),
110120
resources.NewKinesisFirehose(),
111121
resources.NewKinesisStreams(),
112-
&resources.KmsCustomerKeys{},
113-
&resources.LambdaFunctions{},
114-
&resources.LambdaLayers{},
122+
resources.NewKmsCustomerKeys(),
123+
resources.NewLambdaFunctions(),
124+
resources.NewLambdaLayers(),
115125
resources.NewLaunchConfigs(),
116126
resources.NewLaunchTemplates(),
117-
&resources.MacieMember{},
118-
&resources.MSKCluster{},
127+
resources.NewMacieMember(),
128+
resources.NewMSKCluster(),
119129
resources.NewNatGateways(),
120-
&resources.OpenSearchDomains{},
121-
&resources.DBGlobalClusterMemberships{},
122-
&resources.DBInstances{},
123-
&resources.DBSubnetGroups{},
124-
&resources.DBClusters{},
130+
resources.NewOpenSearchDomains(),
131+
resources.NewDBGlobalClusterMemberships(),
132+
resources.NewDBInstances(),
133+
resources.NewDBSubnetGroups(),
134+
resources.NewDBClusters(),
125135
resources.NewRdsProxy(),
126136
resources.NewRdsSnapshot(),
127-
&resources.RdsParameterGroup{},
128-
&resources.RedshiftClusters{},
129-
&resources.RedshiftSnapshotCopyGrants{},
130-
&resources.S3Buckets{},
131-
&resources.S3AccessPoint{},
132-
&resources.S3ObjectLambdaAccessPoint{},
133-
&resources.S3MultiRegionAccessPoint{},
134-
&resources.SageMakerNotebookInstances{},
135-
&resources.SageMakerStudio{},
136-
&resources.SageMakerEndpoint{},
137+
resources.NewRdsParameterGroup(),
138+
resources.NewRedshiftClusters(),
139+
resources.NewRedshiftSnapshotCopyGrants(),
140+
resources.NewS3AccessPoints(),
141+
resources.NewS3ObjectLambdaAccessPoints(),
142+
resources.NewS3MultiRegionAccessPoints(),
143+
resources.NewSageMakerNotebookInstances(),
144+
resources.NewSageMakerStudio(),
145+
resources.NewSageMakerEndpoint(),
146+
resources.NewSageMakerEndpointConfig(),
137147
resources.NewSecretsManagerSecrets(),
138-
&resources.SecurityHub{},
148+
resources.NewSecurityHub(),
139149
resources.NewSesConfigurationSet(),
140150
resources.NewSesEmailTemplates(),
141151
resources.NewSesIdentities(),
142-
&resources.SesReceiptRule{},
143-
&resources.SesReceiptFilter{},
152+
resources.NewSesReceiptRule(),
153+
resources.NewSesReceiptFilter(),
144154
resources.NewSnapshots(),
145155
resources.NewSNSTopic(),
146156
resources.NewSqsQueue(),
147-
&resources.EC2IPAMs{},
148-
&resources.EC2IpamScopes{},
149-
&resources.EC2IPAMResourceDiscovery{},
150-
&resources.EC2IPAMPool{},
151-
&resources.EC2IPAMByoasn{},
152-
&resources.EC2IPAMCustomAllocation{},
153-
&resources.EC2Subnet{},
154-
&resources.InternetGateway{},
155-
&resources.NetworkInterface{},
156-
&resources.SecurityGroup{},
157-
&resources.NetworkACL{},
158-
&resources.NetworkFirewall{},
159-
&resources.NetworkFirewallPolicy{},
160-
&resources.NetworkFirewallRuleGroup{},
161-
&resources.NetworkFirewallTLSConfig{},
162-
&resources.NetworkFirewallResourcePolicy{},
163-
&resources.VPCLatticeServiceNetwork{},
164-
&resources.VPCLatticeService{},
165-
&resources.VPCLatticeTargetGroup{},
166-
// Note: VPCs must be deleted last after all resources that create network interfaces (EKS, ECS, etc.)
167-
&resources.EC2VPCs{},
168-
// Note: nuking EC2 DHCP options after nuking EC2 VPC because DHCP options could be associated with VPCs.
169-
&resources.EC2DhcpOption{},
157+
resources.NewEC2IPAM(),
158+
resources.NewEC2IPAMScope(),
159+
resources.NewEC2IPAMResourceDiscovery(),
160+
resources.NewEC2IPAMPool(),
161+
resources.NewEC2IPAMByoasn(),
162+
resources.NewEC2IPAMCustomAllocation(),
163+
resources.NewNetworkFirewalls(),
164+
resources.NewNetworkFirewallPolicy(),
165+
resources.NewNetworkFirewallRuleGroup(),
166+
resources.NewNetworkFirewallTLSConfig(),
167+
resources.NewNetworkFirewallResourcePolicy(),
168+
resources.NewVPCLatticeServiceNetwork(),
169+
resources.NewVPCLatticeService(),
170+
resources.NewVPCLatticeTargetGroup(),
171+
// Note: VPC deletion order per AWS docs (https://docs.aws.amazon.com/vpc/latest/userguide/delete-vpc.html):
172+
// 1. Network Interfaces (ENIs must be deleted before security groups and subnets)
173+
resources.NewNetworkInterface(),
174+
// 2. Security Groups (must be deleted before VPC, after ENIs that reference them)
175+
resources.NewSecurityGroup(),
176+
// 3. Network ACLs (must be deleted before subnets)
177+
resources.NewNetworkACL(),
178+
// 4. Subnets (after ENIs, security groups, network ACLs)
179+
resources.NewEC2Subnet(),
180+
// 5. Internet Gateways (detach and delete before VPC)
181+
resources.NewInternetGateway(),
182+
// 6. VPCs (must be deleted last after all VPC-dependent resources)
183+
resources.NewEC2VPC(),
184+
// 7. DHCP Options (can be deleted after VPC since they're just disassociated)
185+
resources.NewEC2DhcpOptions(),
170186
}
171187
}
172188

aws/resources/access_analyzer.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"github.com/aws/aws-sdk-go-v2/aws"
77
"github.com/aws/aws-sdk-go-v2/service/accessanalyzer"
88
"github.com/gruntwork-io/cloud-nuke/config"
9-
"github.com/gruntwork-io/cloud-nuke/logging"
109
"github.com/gruntwork-io/cloud-nuke/resource"
1110
)
1211

@@ -21,15 +20,10 @@ func NewAccessAnalyzer() AwsResource {
2120
return NewAwsResource(&resource.Resource[AccessAnalyzerAPI]{
2221
ResourceTypeName: "accessanalyzer",
2322
BatchSize: 10,
24-
InitClient: func(r *resource.Resource[AccessAnalyzerAPI], cfg any) {
25-
awsCfg, ok := cfg.(aws.Config)
26-
if !ok {
27-
logging.Debugf("Invalid config type for AccessAnalyzer client: expected aws.Config")
28-
return
29-
}
30-
r.Scope.Region = awsCfg.Region
31-
r.Client = accessanalyzer.NewFromConfig(awsCfg)
32-
},
23+
InitClient: WrapAwsInitClient(func(r *resource.Resource[AccessAnalyzerAPI], cfg aws.Config) {
24+
r.Scope.Region = cfg.Region
25+
r.Client = accessanalyzer.NewFromConfig(cfg)
26+
}),
3327
ConfigGetter: func(c config.Config) config.ResourceType {
3428
return c.AccessAnalyzer
3529
},

0 commit comments

Comments
 (0)