├── .circleci ├── config.yml └── nuke_config.yml ├── .github ├── FUNDING.yml └── pull_request_template.md ├── .gitignore ├── .gon_amd64.hcl ├── .gon_arm64.hcl ├── .pre-commit-config.yaml ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── _docs └── rfc │ └── TEMPLATE.md ├── aws ├── aws.go ├── aws_test.go ├── error.go ├── inspect.go ├── inspect_test.go ├── query.go ├── query_test.go ├── region.go ├── region_test.go ├── resource.go ├── resource_registry.go └── resources │ ├── access_analyzer.go │ ├── access_analyzer_test.go │ ├── access_analyzer_types.go │ ├── acm.go │ ├── acm_test.go │ ├── acm_types.go │ ├── acmpca.go │ ├── acmpca_test.go │ ├── acmpca_types.go │ ├── ami.go │ ├── ami_test.go │ ├── ami_types.go │ ├── apigateway.go │ ├── apigateway_test.go │ ├── apigateway_types.go │ ├── apigatewayv2.go │ ├── apigatewayv2_test.go │ ├── apigatewayv2_types.go │ ├── apprunner_service.go │ ├── apprunner_service_test.go │ ├── apprunner_service_types.go │ ├── asg.go │ ├── asg_test.go │ ├── asg_types.go │ ├── backup_vault.go │ ├── backup_vault_test.go │ ├── backup_vault_types.go │ ├── base_resource.go │ ├── cloudfront_distribution.go │ ├── cloudfront_distribution_test.go │ ├── cloudfront_distribution_types.go │ ├── cloudtrail.go │ ├── cloudtrail_test.go │ ├── cloudtrail_types.go │ ├── cloudwatch_alarm.go │ ├── cloudwatch_alarm_test.go │ ├── cloudwatch_alarm_types.go │ ├── cloudwatch_dashboard.go │ ├── cloudwatch_dashboard_test.go │ ├── cloudwatch_dashboard_types.go │ ├── cloudwatch_loggroup.go │ ├── cloudwatch_loggroup_test.go │ ├── cloudwatch_loggroup_types.go │ ├── codedeploy_application.go │ ├── codedeploy_application_test.go │ ├── codedeploy_application_types.go │ ├── common.go │ ├── config_recorder.go │ ├── config_recorder_test.go │ ├── config_recorder_types.go │ ├── config_service.go │ ├── config_service_test.go │ ├── config_service_types.go │ ├── datasync_location.go │ ├── datasync_location_test.go │ ├── datasync_location_types.go │ ├── datasync_task.go │ ├── datasync_task_test.go │ ├── datasync_task_types.go │ ├── dynamodb.go │ ├── dynamodb_test.go │ ├── dynamodb_types.go │ ├── ebs.go │ ├── ebs_test.go │ ├── ebs_types.go │ ├── ec2.go │ ├── ec2_dedicated_host.go │ ├── ec2_dedicated_host_test.go │ ├── ec2_dedicated_host_types.go │ ├── ec2_dhcp_option.go │ ├── ec2_dhcp_option_test.go │ ├── ec2_dhcp_option_types.go │ ├── ec2_egress_only_igw.go │ ├── ec2_egress_only_igw_test.go │ ├── ec2_egress_only_igw_types.go │ ├── ec2_endpoints.go │ ├── ec2_endpoints_test.go │ ├── ec2_endpoints_types.go │ ├── ec2_internet_gateway.go │ ├── ec2_internet_gateway_test.go │ ├── ec2_internet_gateway_types.go │ ├── ec2_ipam.go │ ├── ec2_ipam_byoasn.go │ ├── ec2_ipam_byoasn_test.go │ ├── ec2_ipam_byoasn_types.go │ ├── ec2_ipam_custom_allocation.go │ ├── ec2_ipam_custom_allocation_test.go │ ├── ec2_ipam_custom_allocation_types.go │ ├── ec2_ipam_pool.go │ ├── ec2_ipam_pool_test.go │ ├── ec2_ipam_pool_types.go │ ├── ec2_ipam_resource_discovery.go │ ├── ec2_ipam_resource_discovery_test.go │ ├── ec2_ipam_resource_discovery_types.go │ ├── ec2_ipam_scope.go │ ├── ec2_ipam_scope_test.go │ ├── ec2_ipam_scope_types.go │ ├── ec2_ipam_test.go │ ├── ec2_ipam_types.go │ ├── ec2_key_pair.go │ ├── ec2_key_pair_test.go │ ├── ec2_key_pair_types.go │ ├── ec2_network_acl.go │ ├── ec2_network_acl_test.go │ ├── ec2_network_acl_types.go │ ├── ec2_network_interface.go │ ├── ec2_network_interface_test.go │ ├── ec2_network_interface_types.go │ ├── ec2_placement_group.go │ ├── ec2_placement_group_test.go │ ├── ec2_placement_group_types.go │ ├── ec2_subnet.go │ ├── ec2_subnet_test.go │ ├── ec2_subnet_types.go │ ├── ec2_test.go │ ├── ec2_types.go │ ├── ec2_vpc.go │ ├── ec2_vpc_test.go │ ├── ec2_vpc_types.go │ ├── ecr.go │ ├── ecr_test.go │ ├── ecr_types.go │ ├── ecs_cluster.go │ ├── ecs_cluster_test.go │ ├── ecs_cluster_types.go │ ├── ecs_service.go │ ├── ecs_service_test.go │ ├── ecs_service_types.go │ ├── efs.go │ ├── efs_test.go │ ├── efs_types.go │ ├── eip.go │ ├── eip_test.go │ ├── eip_types.go │ ├── eks.go │ ├── eks_test.go │ ├── eks_types.go │ ├── elastic_beanstalk.go │ ├── elastic_beanstalk_test.go │ ├── elastic_beanstalk_types.go │ ├── elasticache.go │ ├── elasticache_serverless.go │ ├── elasticache_serverless_test.go │ ├── elasticache_serverless_types.go │ ├── elasticache_test.go │ ├── elasticache_types.go │ ├── elb.go │ ├── elb_test.go │ ├── elb_types.go │ ├── elbv2.go │ ├── elbv2_test.go │ ├── elbv2_types.go │ ├── eventbridge.go │ ├── eventbridge_archive.go │ ├── eventbridge_archive_test.go │ ├── eventbridge_archive_types.go │ ├── eventbridge_rule.go │ ├── eventbridge_rule_test.go │ ├── eventbridge_rule_types.go │ ├── eventbridge_schedule.go │ ├── eventbridge_schedule_group.go │ ├── eventbridge_schedule_group_test.go │ ├── eventbridge_schedule_group_types.go │ ├── eventbridge_schedule_test.go │ ├── eventbridge_schedule_types.go │ ├── eventbridge_test.go │ ├── eventbridge_types.go │ ├── globals.go │ ├── grafana.go │ ├── grafana_test.go │ ├── grafana_types.go │ ├── guardduty.go │ ├── guardduty_test.go │ ├── guardduty_types.go │ ├── iam.go │ ├── iam_group.go │ ├── iam_group_test.go │ ├── iam_group_types.go │ ├── iam_instance_profile.go │ ├── iam_instance_profile_test.go │ ├── iam_instance_profile_types.go │ ├── iam_policy.go │ ├── iam_policy_test.go │ ├── iam_policy_types.go │ ├── iam_role.go │ ├── iam_role_test.go │ ├── iam_role_types.go │ ├── iam_service_linked_role.go │ ├── iam_service_linked_role_test.go │ ├── iam_service_linked_role_types.go │ ├── iam_test.go │ ├── iam_types.go │ ├── kinesis_firehose.go │ ├── kinesis_firehose_test.go │ ├── kinesis_firehose_types.go │ ├── kinesis_stream.go │ ├── kinesis_stream_test.go │ ├── kinesis_stream_types.go │ ├── kms_customer_key.go │ ├── kms_customer_key_test.go │ ├── kms_customer_key_types.go │ ├── lambda.go │ ├── lambda_layer.go │ ├── lambda_layer_test.go │ ├── lambda_layer_types.go │ ├── lambda_test.go │ ├── lambda_types.go │ ├── launch_config.go │ ├── launch_config_test.go │ ├── launch_config_types.go │ ├── launch_template.go │ ├── launch_template_test.go │ ├── launch_template_types.go │ ├── macie.go │ ├── macie_test.go │ ├── macie_types.go │ ├── managed_prometheus.go │ ├── managed_prometheus_test.go │ ├── managed_prometheus_types.go │ ├── msk_cluster.go │ ├── msk_cluster_test.go │ ├── msk_cluster_types.go │ ├── nat_gateway.go │ ├── nat_gateway_test.go │ ├── nat_gateway_types.go │ ├── network_firewall.go │ ├── network_firewall_policy.go │ ├── network_firewall_policy_test.go │ ├── network_firewall_policy_types.go │ ├── network_firewall_resource_policy.go │ ├── network_firewall_resource_policy_test.go │ ├── network_firewall_resource_policy_types.go │ ├── network_firewall_rule_group.go │ ├── network_firewall_rule_group_test.go │ ├── network_firewall_rule_group_types.go │ ├── network_firewall_test.go │ ├── network_firewall_tls_config.go │ ├── network_firewall_tls_config_test.go │ ├── network_firewall_tls_config_types.go │ ├── network_firewall_types.go │ ├── oidc_provider.go │ ├── oidc_provider_test.go │ ├── oidc_provider_types.go │ ├── opensearch.go │ ├── opensearch_test.go │ ├── opensearch_types.go │ ├── rds.go │ ├── rds_cluster.go │ ├── rds_cluster_test.go │ ├── rds_cluster_types.go │ ├── rds_global_cluster.go │ ├── rds_global_cluster_membership.go │ ├── rds_global_cluster_membership_test.go │ ├── rds_global_cluster_membership_types.go │ ├── rds_global_cluster_test.go │ ├── rds_global_cluster_types.go │ ├── rds_parameter_group.go │ ├── rds_parameter_group_test.go │ ├── rds_parameter_group_types.go │ ├── rds_proxy.go │ ├── rds_proxy_test.go │ ├── rds_proxy_types.go │ ├── rds_snapshot.go │ ├── rds_snapshot_test.go │ ├── rds_snapshot_types.go │ ├── rds_subnet_group.go │ ├── rds_subnet_group_test.go │ ├── rds_subnet_group_types.go │ ├── rds_test.go │ ├── rds_types.go │ ├── redshift.go │ ├── redshift_test.go │ ├── redshift_types.go │ ├── route53_cidr_collection.go │ ├── route53_cidr_collection_test.go │ ├── route53_cidr_collection_types.go │ ├── route53_hostedzone.go │ ├── route53_hostedzone_test.go │ ├── route53_hostedzone_types.go │ ├── route53_traffic_policy.go │ ├── route53_traffic_policy_test.go │ ├── route53_traffic_policy_types.go │ ├── s3.go │ ├── s3_access_point.go │ ├── s3_access_point_test.go │ ├── s3_access_point_types.go │ ├── s3_multi_region_access_point.go │ ├── s3_multi_region_access_point_test.go │ ├── s3_multi_region_access_point_types.go │ ├── s3_object_lambda_access_point.go │ ├── s3_object_lambda_access_point_test.go │ ├── s3_object_lambda_access_point_types.go │ ├── s3_test.go │ ├── s3_types.go │ ├── sagemaker_endpoint.go │ ├── sagemaker_endpoint_config.go │ ├── sagemaker_endpoint_config_test.go │ ├── sagemaker_endpoint_config_types.go │ ├── sagemaker_endpoint_test.go │ ├── sagemaker_endpoint_types.go │ ├── sagemaker_notebook_instance.go │ ├── sagemaker_notebook_instance_test.go │ ├── sagemaker_notebook_instance_types.go │ ├── sagemaker_studio.go │ ├── sagemaker_studio_test.go │ ├── sagemaker_studio_types.go │ ├── secrets_manager.go │ ├── secrets_manager_test.go │ ├── secrets_manager_types.go │ ├── security_group.go │ ├── security_group_test.go │ ├── security_group_types.go │ ├── security_hub.go │ ├── security_hub_test.go │ ├── security_hub_types.go │ ├── ses_configuration_set.go │ ├── ses_configuration_set_test.go │ ├── ses_configuration_set_types.go │ ├── ses_email_receiving.go │ ├── ses_email_receiving_test.go │ ├── ses_email_receiving_types.go │ ├── ses_email_templates.go │ ├── ses_email_templates_test.go │ ├── ses_email_templates_types.go │ ├── ses_identity.go │ ├── ses_identity_test.go │ ├── ses_identity_types.go │ ├── snapshot.go │ ├── snapshot_test.go │ ├── snapshot_types.go │ ├── sns.go │ ├── sns_test.go │ ├── sns_types.go │ ├── sqs.go │ ├── sqs_test.go │ ├── sqs_types.go │ ├── tgw_peering_attachment.go │ ├── tgw_peering_attachment_test.go │ ├── tgw_peering_attachment_types.go │ ├── tgw_route_tables.go │ ├── tgw_route_tables_test.go │ ├── tgw_route_tables_types.go │ ├── tgw_vpc_attachment.go │ ├── tgw_vpc_attachment_test.go │ ├── tgw_vpc_attachment_types.go │ ├── transit_gateway.go │ ├── transit_gateway_test.go │ ├── transit_gateway_types.go │ ├── vpc_lattice_service.go │ ├── vpc_lattice_service_network.go │ ├── vpc_lattice_service_network_test.go │ ├── vpc_lattice_service_network_types.go │ ├── vpc_lattice_service_test.go │ ├── vpc_lattice_service_type.go │ ├── vpc_lattice_target_group.go │ ├── vpc_lattice_target_group_test.go │ └── vpc_lattice_target_group_types.go ├── commands ├── cli.go ├── cli_test.go └── errors.go ├── config ├── config.go ├── config_test.go ├── examples │ ├── complete.yaml │ └── simple.yaml └── mocks │ ├── empty.yaml │ ├── garbage.yaml │ └── malformed.yaml ├── externalcreds └── creds.go ├── gcp ├── gcp.go ├── resource.go └── resources │ ├── base_resource.go │ ├── gcs_bucket.go │ ├── gcs_bucket_test.go │ └── gcs_bucket_types.go ├── go.mod ├── go.sum ├── logging └── logger.go ├── main.go ├── report ├── report.go └── report_test.go ├── telemetry └── telemetry.go ├── ui ├── styles.go ├── ui.go └── ui_test.go └── util ├── context.go ├── error.go ├── error_test.go ├── get_current_account_id.go ├── string_utils.go ├── tag.go ├── time.go ├── time_test.go └── unique_id.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: gruntwork-io 4 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | Fixes #000. 6 | 7 | 8 | 9 | ## TODOs 10 | 11 | Read the [Gruntwork contribution guidelines](https://gruntwork.notion.site/Gruntwork-Coding-Methodology-02fdcd6e4b004e818553684760bf691e). 12 | 13 | - [ ] Update the docs. 14 | - [ ] Run the relevant tests successfully, including pre-commit checks. 15 | - [ ] Ensure any 3rd party code adheres with our [license policy](https://www.notion.so/gruntwork/Gruntwork-licenses-and-open-source-usage-policy-f7dece1f780341c7b69c1763f22b1378) or delete this line if its not applicable. 16 | - [ ] Include release notes. If this PR is backward incompatible, include a migration guide. 17 | - [ ] Attention Grunts - if this PR adds support for a new resource, ensure the `nuke_sandbox` and `nuke_phxdevops` jobs in `.circleci/config.yml` have been updated with appropriate exclusions (either directly in the job or via the `.circleci/nuke_config.yml` file) to prevent nuking IAM roles, groups, resources, etc that are important for the test accounts. 18 | 19 | 20 | ## Release Notes (draft) 21 | 22 | 23 | Added / Removed / Updated [X]. 24 | 25 | ### Migration Guide 26 | 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | .vscode 4 | cloud-nuke 5 | config.yaml 6 | .envrc 7 | -------------------------------------------------------------------------------- /.gon_amd64.hcl: -------------------------------------------------------------------------------- 1 | # See https://github.com/gruntwork-io/terraform-aws-ci/blob/main/modules/sign-binary-helpers/ 2 | # for further instructions on how to sign the binary + submitting for notarization. 3 | 4 | source = ["./bin/cloud-nuke_darwin_amd64"] 5 | 6 | bundle_id = "io.gruntwork.app.terragrunt" 7 | 8 | apple_id { 9 | username = "machine.apple@gruntwork.io" 10 | } 11 | 12 | sign { 13 | application_identity = "Developer ID Application: Gruntwork, Inc." 14 | } 15 | 16 | zip { 17 | output_path = "cloud-nuke_darwin_amd64.zip" 18 | } 19 | -------------------------------------------------------------------------------- /.gon_arm64.hcl: -------------------------------------------------------------------------------- 1 | # See https://github.com/gruntwork-io/terraform-aws-ci/blob/main/modules/sign-binary-helpers/ 2 | # for further instructions on how to sign the binary + submitting for notarization. 3 | 4 | source = ["./bin/cloud-nuke_darwin_arm64"] 5 | 6 | bundle_id = "io.gruntwork.app.terragrunt" 7 | 8 | apple_id { 9 | username = "machine.apple@gruntwork.io" 10 | } 11 | 12 | sign { 13 | application_identity = "Developer ID Application: Gruntwork, Inc." 14 | } 15 | 16 | zip { 17 | output_path = "cloud-nuke_darwin_arm64.zip" 18 | } 19 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: check-case-conflict 6 | - id: trailing-whitespace 7 | - id: end-of-file-fixer 8 | - id: check-added-large-files 9 | - repo: https://github.com/gruntwork-io/pre-commit 10 | rev: v0.1.25 11 | hooks: 12 | - id: shellcheck 13 | - id: gofmt 14 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @arsci @denis256 @james03160927 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020, Gruntwork, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /_docs/rfc/TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # RFC Template 2 | 3 | This is a template you can use for proposing new major features to `cloud-nuke`. When creating a new RFC, copy this 4 | template and fill in each respective section. 5 | 6 | **STATUS**: In proposal _(This should be updated when you open a PR for the implementation)_ 7 | 8 | 9 | ## Background 10 | 11 | This section should describe why you need this feature in `cloud-nuke`. This should include a description of: 12 | 13 | - The problem you are trying to solve. 14 | implementation that it makes sense to workaround it in Terragrunt. 15 | - Use cases for the problem. Why is it important that we have this feature? 16 | 17 | 18 | ## Proposed solution 19 | 20 | This section should describe which solution you are ultimately picking for implementation. This should describe in 21 | detail how this solution addresses the problem. Additionally, this section should include implementation details. Be 22 | sure to include code samples so that it is clear how users are intended to use the solution you are proposing! 23 | 24 | Note: This section can be left blank in the initial PR, if you are unsure what the best solution is. In this case, 25 | include all the possible solutions you can think of as a part of the `Alternatives` section below. You can fill this 26 | section out once you feel confident in a potential approach after discussion on the PR. 27 | 28 | 29 | ## Alternatives 30 | 31 | This section should describe various options for resolving the problem stated in the `Background` section. Be sure to 32 | include various alternatives here and not just the one you are ultimately proposing. This helps communicate what 33 | tradeoffs you are making in picking your solution. Any reasonably complex problem that requires an RFC have multiple 34 | solutions that appear to be valid, so it helps to be explicit about why certain solutions were not chosen. 35 | 36 | 37 | ## References 38 | 39 | This section should include any links that are helpful for background reading such as: 40 | 41 | - Relevant issues 42 | - Links to PRs: at a minimum, the initial PR for the RFC, and the implementation PR. 43 | - Links to `cloud-nuke` releases, if the proposed solution has been implemented. 44 | -------------------------------------------------------------------------------- /aws/error.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import "fmt" 4 | 5 | type CouldNotSelectRegionError struct { 6 | Underlying error 7 | } 8 | 9 | func (err CouldNotSelectRegionError) Error() string { 10 | return fmt.Sprintf("Unable to determine target region set. Please double check your combination of target and excluded regions. Original error: %v", err.Underlying) 11 | } 12 | 13 | type CouldNotDetermineEnabledRegionsError struct { 14 | Underlying error 15 | } 16 | 17 | func (err CouldNotDetermineEnabledRegionsError) Error() string { 18 | return fmt.Sprintf("Unable to determine enabled regions in target account. Original error: %v", err.Underlying) 19 | } 20 | 21 | type InvalidResourceTypesSuppliedError struct { 22 | InvalidTypes []string 23 | } 24 | 25 | func (err InvalidResourceTypesSuppliedError) Error() string { 26 | return fmt.Sprintf("Invalid resourceTypes %s specified: %s", err.InvalidTypes, "Try --list-resource-types to get a list of valid resource types.") 27 | } 28 | 29 | type ResourceTypeAndExcludeFlagsBothPassedError struct{} 30 | 31 | func (err ResourceTypeAndExcludeFlagsBothPassedError) Error() string { 32 | return "You can not specify both --resource-type and --exclude-resource-type" 33 | } 34 | 35 | type InvalidTimeStringPassedError struct { 36 | Entry string 37 | Underlying error 38 | } 39 | 40 | func (err InvalidTimeStringPassedError) Error() string { 41 | return fmt.Sprintf("Could not parse %s as a valid time duration. Underlying error: %s", err.Entry, err.Underlying) 42 | } 43 | 44 | type QueryCreationError struct { 45 | Underlying error 46 | } 47 | 48 | func (err QueryCreationError) Error() string { 49 | return fmt.Sprintf("Error forming a cloud-nuke Query with supplied parameters. Original error: %v", err.Underlying) 50 | } 51 | 52 | type ResourceInspectionError struct { 53 | Underlying error 54 | } 55 | 56 | func (err ResourceInspectionError) Error() string { 57 | return fmt.Sprintf("Error encountered when querying for account resources. Original error: %v", err.Underlying) 58 | } 59 | -------------------------------------------------------------------------------- /aws/inspect.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "github.com/gruntwork-io/go-commons/collections" 5 | ) 6 | 7 | func ensureValidResourceTypes(resourceTypes []string) ([]string, error) { 8 | invalidresourceTypes := []string{} 9 | for _, resourceType := range resourceTypes { 10 | if resourceType == "all" { 11 | continue 12 | } 13 | if !IsValidResourceType(resourceType, ListResourceTypes()) { 14 | invalidresourceTypes = append(invalidresourceTypes, resourceType) 15 | } 16 | } 17 | 18 | if len(invalidresourceTypes) > 0 { 19 | return []string{}, InvalidResourceTypesSuppliedError{InvalidTypes: invalidresourceTypes} 20 | } 21 | 22 | return resourceTypes, nil 23 | } 24 | 25 | // HandleResourceTypeSelections accepts a slice of target resourceTypes and a slice of resourceTypes to exclude. It filters 26 | // any excluded or invalid types from target resourceTypes then returns the filtered slice 27 | func HandleResourceTypeSelections( 28 | includeResourceTypes, excludeResourceTypes []string, 29 | ) ([]string, error) { 30 | if len(includeResourceTypes) > 0 && len(excludeResourceTypes) > 0 { 31 | return []string{}, ResourceTypeAndExcludeFlagsBothPassedError{} 32 | } 33 | 34 | if len(includeResourceTypes) > 0 { 35 | return ensureValidResourceTypes(includeResourceTypes) 36 | } 37 | 38 | // Handle exclude resource types by going through the list of all types and only include those that are not 39 | // mentioned in the exclude list. 40 | validExcludeResourceTypes, err := ensureValidResourceTypes(excludeResourceTypes) 41 | if err != nil { 42 | return []string{}, err 43 | } 44 | 45 | resourceTypes := []string{} 46 | for _, resourceType := range ListResourceTypes() { 47 | if !collections.ListContainsElement(validExcludeResourceTypes, resourceType) { 48 | resourceTypes = append(resourceTypes, resourceType) 49 | } 50 | } 51 | return resourceTypes, nil 52 | } 53 | -------------------------------------------------------------------------------- /aws/query_test.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/aws/aws-sdk-go-v2/aws" 8 | 9 | "github.com/gruntwork-io/cloud-nuke/telemetry" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | func TestNewQueryAcceptsValidExcludeAfterEntries(t *testing.T) { 16 | telemetry.InitTelemetry("cloud-nuke", "") 17 | type TestCase struct { 18 | Name string 19 | Regions []string 20 | ExcludeRegions []string 21 | ResourceTypes []string 22 | ExcludeResourceTypes []string 23 | ExcludeAfter *time.Time 24 | IncludeAfter *time.Time 25 | } 26 | 27 | testCases := []TestCase{ 28 | { 29 | Name: "Can pass time.Now plus 24 hours", 30 | Regions: []string{"us-east-1"}, 31 | ExcludeRegions: []string{}, 32 | ResourceTypes: []string{"ec2"}, 33 | ExcludeAfter: aws.Time(time.Now().Add(time.Hour * 24)), 34 | IncludeAfter: aws.Time(time.Now().Add(time.Hour * 24)), 35 | }, 36 | { 37 | Name: "Can pass time.Now", 38 | Regions: []string{"us-east-1"}, 39 | ExcludeRegions: []string{}, 40 | ResourceTypes: []string{"ec2"}, 41 | ExcludeAfter: aws.Time(time.Now()), 42 | IncludeAfter: aws.Time(time.Now()), 43 | }, 44 | } 45 | 46 | for _, tc := range testCases { 47 | t.Run(tc.Name, func(t *testing.T) { 48 | q, err := NewQuery( 49 | tc.Regions, 50 | tc.ExcludeRegions, 51 | tc.ResourceTypes, 52 | tc.ExcludeResourceTypes, 53 | tc.ExcludeAfter, 54 | tc.IncludeAfter, 55 | false, 56 | nil, 57 | false, 58 | false, 59 | ) 60 | require.NoError(t, err) 61 | assert.True(t, q.ProtectUntilExpire) 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /aws/region_test.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestGlobalRegion(t *testing.T) { 11 | t.Run("NoEnv", func(t *testing.T) { 12 | c, err := NewSession(GlobalRegion) 13 | require.NoError(t, err) 14 | assert.Equal(t, DefaultRegion, c.Region) 15 | 16 | }) 17 | 18 | t.Run("WithEnv", func(t *testing.T) { 19 | global := "us-gov-east-1" 20 | t.Setenv("CLOUD_NUKE_AWS_GLOBAL_REGION", global) 21 | c, err := NewSession(GlobalRegion) 22 | require.NoError(t, err) 23 | assert.Equal(t, global, c.Region) 24 | }) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /aws/resources/acm_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/acm" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type ACMServiceAPI interface { 13 | DeleteCertificate(ctx context.Context, params *acm.DeleteCertificateInput, optFns ...func(*acm.Options)) (*acm.DeleteCertificateOutput, error) 14 | ListCertificates(ctx context.Context, params *acm.ListCertificatesInput, optFns ...func(*acm.Options)) (*acm.ListCertificatesOutput, error) 15 | } 16 | 17 | // ACM - represents all ACM 18 | type ACM struct { 19 | BaseAwsResource 20 | Client ACMServiceAPI 21 | Region string 22 | ARNs []string 23 | } 24 | 25 | func (a *ACM) Init(cfg aws.Config) { 26 | a.Client = acm.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (a *ACM) ResourceName() string { 31 | return "acm" 32 | } 33 | 34 | // ResourceIdentifiers - the arns of the aws certificate manager certificates 35 | func (a *ACM) ResourceIdentifiers() []string { 36 | return a.ARNs 37 | } 38 | 39 | func (a *ACM) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle 41 | return 10 42 | } 43 | 44 | // GetAndSetResourceConfig To get the resource configuration 45 | func (a *ACM) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 46 | return configObj.ACM 47 | } 48 | 49 | func (a *ACM) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 50 | identifiers, err := a.getAll(c, configObj) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | a.ARNs = aws.ToStringSlice(identifiers) 56 | return a.ARNs, nil 57 | } 58 | 59 | // Nuke - nuke 'em all!!! 60 | func (a *ACM) Nuke(arns []string) error { 61 | if err := a.nukeAll(aws.StringSlice(arns)); err != nil { 62 | return errors.WithStackTrace(err) 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /aws/resources/acmpca_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/acmpca" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type ACMPCAServiceAPI interface { 13 | DeleteCertificateAuthority(ctx context.Context, params *acmpca.DeleteCertificateAuthorityInput, optFns ...func(*acmpca.Options)) (*acmpca.DeleteCertificateAuthorityOutput, error) 14 | DescribeCertificateAuthority(ctx context.Context, params *acmpca.DescribeCertificateAuthorityInput, optFns ...func(*acmpca.Options)) (*acmpca.DescribeCertificateAuthorityOutput, error) 15 | ListCertificateAuthorities(ctx context.Context, params *acmpca.ListCertificateAuthoritiesInput, optFns ...func(*acmpca.Options)) (*acmpca.ListCertificateAuthoritiesOutput, error) 16 | UpdateCertificateAuthority(ctx context.Context, params *acmpca.UpdateCertificateAuthorityInput, optFns ...func(*acmpca.Options)) (*acmpca.UpdateCertificateAuthorityOutput, error) 17 | } 18 | 19 | // ACMPCA - represents all ACMPA 20 | type ACMPCA struct { 21 | BaseAwsResource 22 | Client ACMPCAServiceAPI 23 | Region string 24 | ARNs []string 25 | } 26 | 27 | func (ap *ACMPCA) Init(cfg aws.Config) { 28 | ap.Client = acmpca.NewFromConfig(cfg) 29 | } 30 | 31 | // ResourceName - the simple name of the aws resource 32 | func (ap *ACMPCA) ResourceName() string { 33 | return "acmpca" 34 | } 35 | 36 | // ResourceIdentifiers - The volume ids of the ebs volumes 37 | func (ap *ACMPCA) ResourceIdentifiers() []string { 38 | return ap.ARNs 39 | } 40 | 41 | func (ap *ACMPCA) MaxBatchSize() int { 42 | // Tentative batch size to ensure AWS doesn't throttle 43 | return 10 44 | } 45 | func (ap *ACMPCA) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 46 | return configObj.ACMPCA 47 | } 48 | 49 | func (ap *ACMPCA) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 50 | identifiers, err := ap.getAll(c, configObj) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | ap.ARNs = aws.ToStringSlice(identifiers) 56 | return ap.ARNs, nil 57 | } 58 | 59 | // Nuke - nuke 'em all!!! 60 | func (ap *ACMPCA) Nuke(arns []string) error { 61 | if err := ap.nukeAll(aws.StringSlice(arns)); err != nil { 62 | return errors.WithStackTrace(err) 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /aws/resources/ami_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type AMIsAPI interface { 13 | DeregisterImage(ctx context.Context, params *ec2.DeregisterImageInput, optFns ...func(*ec2.Options)) (*ec2.DeregisterImageOutput, error) 14 | DescribeImages(ctx context.Context, params *ec2.DescribeImagesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeImagesOutput, error) 15 | } 16 | 17 | // AMIs - represents all user owned AMIs 18 | type AMIs struct { 19 | BaseAwsResource 20 | Client AMIsAPI 21 | Region string 22 | ImageIds []string 23 | } 24 | 25 | func (ami *AMIs) Init(cfg aws.Config) { 26 | ami.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (ami *AMIs) ResourceName() string { 31 | return "ami" 32 | } 33 | 34 | // ResourceIdentifiers - The AMI image ids 35 | func (ami *AMIs) ResourceIdentifiers() []string { 36 | return ami.ImageIds 37 | } 38 | 39 | func (ami *AMIs) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle 41 | return 49 42 | } 43 | 44 | func (ami *AMIs) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.AMI 46 | } 47 | 48 | func (ami *AMIs) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := ami.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | ami.ImageIds = aws.ToStringSlice(identifiers) 55 | return ami.ImageIds, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (ami *AMIs) Nuke(identifiers []string) error { 60 | if err := ami.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | 67 | type ImageAvailableError struct{} 68 | 69 | func (e ImageAvailableError) Error() string { 70 | return "Image didn't become available within wait attempts" 71 | } 72 | -------------------------------------------------------------------------------- /aws/resources/apprunner_service_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/apprunner" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type AppRunnerServiceAPI interface { 13 | DeleteService(ctx context.Context, params *apprunner.DeleteServiceInput, optFns ...func(*apprunner.Options)) (*apprunner.DeleteServiceOutput, error) 14 | ListServices(ctx context.Context, params *apprunner.ListServicesInput, optFns ...func(*apprunner.Options)) (*apprunner.ListServicesOutput, error) 15 | } 16 | 17 | type AppRunnerService struct { 18 | BaseAwsResource 19 | Client AppRunnerServiceAPI 20 | Region string 21 | AppRunners []string 22 | } 23 | 24 | func (a *AppRunnerService) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.AppRunnerService 26 | } 27 | 28 | func (a *AppRunnerService) Init(cfg aws.Config) { 29 | a.Client = apprunner.NewFromConfig(cfg) 30 | } 31 | 32 | func (a *AppRunnerService) ResourceName() string { return "app-runner-service" } 33 | 34 | func (a *AppRunnerService) ResourceIdentifiers() []string { return a.AppRunners } 35 | 36 | func (a *AppRunnerService) MaxBatchSize() int { return 19 } 37 | 38 | func (a *AppRunnerService) Nuke(identifiers []string) error { 39 | if err := a.nukeAll(aws.StringSlice(identifiers)); err != nil { 40 | return errors.WithStackTrace(err) 41 | } 42 | 43 | return nil 44 | } 45 | 46 | func (a *AppRunnerService) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := a.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | a.AppRunners = aws.ToStringSlice(identifiers) 53 | return a.AppRunners, nil 54 | } 55 | -------------------------------------------------------------------------------- /aws/resources/asg_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/autoscaling" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type ASGroupsAPI interface { 13 | DescribeAutoScalingGroups(ctx context.Context, params *autoscaling.DescribeAutoScalingGroupsInput, optFns ...func(*autoscaling.Options)) (*autoscaling.DescribeAutoScalingGroupsOutput, error) 14 | DeleteAutoScalingGroup(ctx context.Context, params *autoscaling.DeleteAutoScalingGroupInput, optFns ...func(*autoscaling.Options)) (*autoscaling.DeleteAutoScalingGroupOutput, error) 15 | } 16 | 17 | // ASGroups - represents all auto-scaling groups 18 | type ASGroups struct { 19 | BaseAwsResource 20 | Client ASGroupsAPI 21 | Region string 22 | GroupNames []string 23 | } 24 | 25 | func (ag *ASGroups) Init(cfg aws.Config) { 26 | ag.Client = autoscaling.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (ag *ASGroups) ResourceName() string { 31 | return "asg" 32 | } 33 | 34 | func (ag *ASGroups) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The group names of the auto-scaling groups 40 | func (ag *ASGroups) ResourceIdentifiers() []string { 41 | return ag.GroupNames 42 | } 43 | 44 | func (ag *ASGroups) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.AutoScalingGroup 46 | } 47 | func (ag *ASGroups) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 48 | identifiers, err := ag.getAll(c, configObj) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | ag.GroupNames = aws.ToStringSlice(identifiers) 54 | return ag.GroupNames, nil 55 | } 56 | 57 | // Nuke - nuke 'em all!!! 58 | func (ag *ASGroups) Nuke(identifiers []string) error { 59 | if err := ag.nukeAll(aws.StringSlice(identifiers)); err != nil { 60 | return errors.WithStackTrace(err) 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /aws/resources/backup_vault_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/backup" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type BackupVaultAPI interface { 13 | DeleteBackupVault(ctx context.Context, params *backup.DeleteBackupVaultInput, optFns ...func(*backup.Options)) (*backup.DeleteBackupVaultOutput, error) 14 | DeleteRecoveryPoint(ctx context.Context, params *backup.DeleteRecoveryPointInput, optFns ...func(*backup.Options)) (*backup.DeleteRecoveryPointOutput, error) 15 | ListBackupVaults(ctx context.Context, params *backup.ListBackupVaultsInput, optFns ...func(*backup.Options)) (*backup.ListBackupVaultsOutput, error) 16 | ListRecoveryPointsByBackupVault(ctx context.Context, params *backup.ListRecoveryPointsByBackupVaultInput, optFns ...func(*backup.Options)) (*backup.ListRecoveryPointsByBackupVaultOutput, error) 17 | } 18 | 19 | type BackupVault struct { 20 | BaseAwsResource 21 | Client BackupVaultAPI 22 | Region string 23 | Names []string 24 | } 25 | 26 | func (bv *BackupVault) Init(cfg aws.Config) { 27 | bv.Client = backup.NewFromConfig(cfg) 28 | } 29 | 30 | // ResourceName - the simple name of the aws resource 31 | func (bv *BackupVault) ResourceName() string { 32 | return "backup-vault" 33 | } 34 | 35 | // ResourceIdentifiers - The instance ids of the ec2 instances 36 | func (bv *BackupVault) ResourceIdentifiers() []string { 37 | return bv.Names 38 | } 39 | 40 | func (bv *BackupVault) MaxBatchSize() int { 41 | return 50 42 | } 43 | 44 | func (bv *BackupVault) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.BackupVault 46 | } 47 | func (bv *BackupVault) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 48 | identifiers, err := bv.getAll(c, configObj) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | bv.Names = aws.ToStringSlice(identifiers) 54 | return bv.Names, nil 55 | } 56 | 57 | // Nuke - nuke 'em all!!! 58 | func (bv *BackupVault) Nuke(identifiers []string) error { 59 | if err := bv.nukeAll(aws.StringSlice(identifiers)); err != nil { 60 | return errors.WithStackTrace(err) 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /aws/resources/cloudtrail_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/cloudtrail" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type CloudtrailTrailAPI interface { 13 | ListTrails(ctx context.Context, params *cloudtrail.ListTrailsInput, optFns ...func(*cloudtrail.Options)) (*cloudtrail.ListTrailsOutput, error) 14 | DeleteTrail(ctx context.Context, params *cloudtrail.DeleteTrailInput, optFns ...func(*cloudtrail.Options)) (*cloudtrail.DeleteTrailOutput, error) 15 | ListTags(ctx context.Context, params *cloudtrail.ListTagsInput, optFns ...func(*cloudtrail.Options)) (*cloudtrail.ListTagsOutput, error) 16 | } 17 | 18 | // CloudtrailTrail - represents all CloudTrails 19 | type CloudtrailTrail struct { 20 | BaseAwsResource 21 | Client CloudtrailTrailAPI 22 | Region string 23 | Arns []string 24 | } 25 | 26 | func (ct *CloudtrailTrail) Init(cfg aws.Config) { 27 | ct.Client = cloudtrail.NewFromConfig(cfg) 28 | } 29 | 30 | // ResourceName - the simple name of the aws resource 31 | func (ct *CloudtrailTrail) ResourceName() string { 32 | return "cloudtrail" 33 | } 34 | 35 | // ResourceIdentifiers - The instance ids of the ec2 instances 36 | func (ct *CloudtrailTrail) ResourceIdentifiers() []string { 37 | return ct.Arns 38 | } 39 | 40 | func (ct *CloudtrailTrail) MaxBatchSize() int { 41 | return 50 42 | } 43 | 44 | func (ct *CloudtrailTrail) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.CloudtrailTrail 46 | } 47 | 48 | func (ct *CloudtrailTrail) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := ct.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | ct.Arns = aws.ToStringSlice(identifiers) 55 | return ct.Arns, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (ct *CloudtrailTrail) Nuke(identifiers []string) error { 60 | if err := ct.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/cloudwatch_alarm_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/cloudwatch" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type CloudWatchAlarmsAPI interface { 13 | DescribeAlarms(ctx context.Context, params *cloudwatch.DescribeAlarmsInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.DescribeAlarmsOutput, error) 14 | DeleteAlarms(ctx context.Context, params *cloudwatch.DeleteAlarmsInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.DeleteAlarmsOutput, error) 15 | PutCompositeAlarm(ctx context.Context, params *cloudwatch.PutCompositeAlarmInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.PutCompositeAlarmOutput, error) 16 | } 17 | 18 | // CloudWatchAlarms - represents all CloudWatchAlarms that should be deleted. 19 | type CloudWatchAlarms struct { 20 | BaseAwsResource 21 | Client CloudWatchAlarmsAPI 22 | Region string 23 | AlarmNames []string 24 | } 25 | 26 | func (cw *CloudWatchAlarms) Init(cfg aws.Config) { 27 | cw.Client = cloudwatch.NewFromConfig(cfg) 28 | } 29 | 30 | // ResourceName - the simple name of the aws resource 31 | func (cw *CloudWatchAlarms) ResourceName() string { 32 | return "cloudwatch-alarm" 33 | } 34 | 35 | // ResourceIdentifiers - The name of cloudwatch alarms 36 | func (cw *CloudWatchAlarms) ResourceIdentifiers() []string { 37 | return cw.AlarmNames 38 | } 39 | 40 | func (cw *CloudWatchAlarms) MaxBatchSize() int { 41 | return 99 42 | } 43 | 44 | func (cw *CloudWatchAlarms) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.CloudWatchAlarm 46 | } 47 | 48 | func (cw *CloudWatchAlarms) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := cw.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | cw.AlarmNames = aws.ToStringSlice(identifiers) 55 | return cw.AlarmNames, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (cw *CloudWatchAlarms) Nuke(identifiers []string) error { 60 | if err := cw.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/cloudwatch_dashboard_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/cloudwatch" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type CloudWatchDashboardsAPI interface { 13 | ListDashboards(ctx context.Context, params *cloudwatch.ListDashboardsInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.ListDashboardsOutput, error) 14 | DeleteDashboards(ctx context.Context, params *cloudwatch.DeleteDashboardsInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.DeleteDashboardsOutput, error) 15 | } 16 | 17 | // CloudWatchDashboards - represents all CloudWatch Dashboards that should be deleted. 18 | type CloudWatchDashboards struct { 19 | BaseAwsResource 20 | Client CloudWatchDashboardsAPI 21 | Region string 22 | DashboardNames []string 23 | } 24 | 25 | func (cwdb *CloudWatchDashboards) Init(cfg aws.Config) { 26 | cwdb.Client = cloudwatch.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (cwdb *CloudWatchDashboards) ResourceName() string { 31 | return "cloudwatch-dashboard" 32 | } 33 | 34 | // ResourceIdentifiers - The dashboard names of the cloudwatch dashboards 35 | func (cwdb *CloudWatchDashboards) ResourceIdentifiers() []string { 36 | return cwdb.DashboardNames 37 | } 38 | 39 | func (cwdb *CloudWatchDashboards) MaxBatchSize() int { 40 | return 49 41 | } 42 | 43 | func (cwdb *CloudWatchDashboards) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 44 | return configObj.CloudWatchDashboard 45 | } 46 | func (cwdb *CloudWatchDashboards) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := cwdb.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | cwdb.DashboardNames = aws.ToStringSlice(identifiers) 53 | return cwdb.DashboardNames, nil 54 | } 55 | 56 | // Nuke - nuke 'em all!!! 57 | func (cwdb *CloudWatchDashboards) Nuke(identifiers []string) error { 58 | if err := cwdb.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /aws/resources/common.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | // The pattern we use for running the `cloud-nuke` tool is to split the AWS API calls 4 | // into batches when the function `NukeAllResources` is executed. 5 | // A batch max number has been chosen for most modules. 6 | // However, for ECS clusters there is no explicit limiting described in the AWS CLI docs. 7 | // Therefore this `maxBatchSize` here is set to 49 as a safe maximum. 8 | 9 | // This constant was moved into `common.go` since it was referenced across multiple resource types 10 | const maxBatchSize = 49 11 | -------------------------------------------------------------------------------- /aws/resources/config_recorder.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/configservice" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | func (csr *ConfigServiceRecorders) getAll(c context.Context, configObj config.Config) ([]*string, error) { 15 | 16 | var configRecorderNames []*string 17 | 18 | param := &configservice.DescribeConfigurationRecordersInput{} 19 | output, err := csr.Client.DescribeConfigurationRecorders(csr.Context, param) 20 | if err != nil { 21 | return []*string{}, errors.WithStackTrace(err) 22 | } 23 | 24 | for _, configRecorder := range output.ConfigurationRecorders { 25 | if configObj.ConfigServiceRecorder.ShouldInclude(config.ResourceValue{ 26 | Name: configRecorder.Name, 27 | }) { 28 | configRecorderNames = append(configRecorderNames, configRecorder.Name) 29 | } 30 | } 31 | 32 | return configRecorderNames, nil 33 | } 34 | 35 | func (csr *ConfigServiceRecorders) nukeAll(configRecorderNames []string) error { 36 | if len(configRecorderNames) == 0 { 37 | logging.Debugf("No Config recorders to nuke in region %s", csr.Region) 38 | return nil 39 | } 40 | 41 | var deletedNames []*string 42 | 43 | for _, configRecorderName := range configRecorderNames { 44 | params := &configservice.DeleteConfigurationRecorderInput{ 45 | ConfigurationRecorderName: aws.String(configRecorderName), 46 | } 47 | 48 | _, err := csr.Client.DeleteConfigurationRecorder(csr.Context, params) 49 | 50 | // Record status of this resource 51 | e := report.Entry{ 52 | Identifier: configRecorderName, 53 | ResourceType: "Config Recorder", 54 | Error: err, 55 | } 56 | report.Record(e) 57 | 58 | if err != nil { 59 | logging.Debugf("[Failed] %s", err) 60 | } else { 61 | deletedNames = append(deletedNames, aws.String(configRecorderName)) 62 | logging.Debugf("Deleted Config Recorder: %s", configRecorderName) 63 | } 64 | } 65 | 66 | logging.Debugf("[OK] %d Config Recorders deleted in %s", len(deletedNames), csr.Region) 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /aws/resources/config_recorder_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/configservice" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type ConfigServiceRecordersAPI interface { 13 | DescribeConfigurationRecorders(ctx context.Context, params *configservice.DescribeConfigurationRecordersInput, optFns ...func(*configservice.Options)) (*configservice.DescribeConfigurationRecordersOutput, error) 14 | DeleteConfigurationRecorder(ctx context.Context, params *configservice.DeleteConfigurationRecorderInput, optFns ...func(*configservice.Options)) (*configservice.DeleteConfigurationRecorderOutput, error) 15 | } 16 | 17 | type ConfigServiceRecorders struct { 18 | BaseAwsResource 19 | Client ConfigServiceRecordersAPI 20 | Region string 21 | RecorderNames []string 22 | } 23 | 24 | func (csr *ConfigServiceRecorders) Init(cfg aws.Config) { 25 | csr.Client = configservice.NewFromConfig(cfg) 26 | } 27 | 28 | func (csr *ConfigServiceRecorders) ResourceName() string { 29 | return "config-recorders" 30 | } 31 | 32 | func (csr *ConfigServiceRecorders) ResourceIdentifiers() []string { 33 | return csr.RecorderNames 34 | } 35 | 36 | func (csr *ConfigServiceRecorders) MaxBatchSize() int { 37 | return 50 38 | } 39 | 40 | func (csr *ConfigServiceRecorders) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 41 | return configObj.ConfigServiceRecorder 42 | } 43 | 44 | func (csr *ConfigServiceRecorders) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := csr.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | csr.RecorderNames = aws.ToStringSlice(identifiers) 51 | return csr.RecorderNames, nil 52 | } 53 | 54 | func (csr *ConfigServiceRecorders) Nuke(configServiceRecorderNames []string) error { 55 | if err := csr.nukeAll(configServiceRecorderNames); err != nil { 56 | return errors.WithStackTrace(err) 57 | } 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /aws/resources/config_service_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/configservice" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type ConfigServiceRuleAPI interface { 13 | DescribeConfigRules(ctx context.Context, params *configservice.DescribeConfigRulesInput, optFns ...func(*configservice.Options)) (*configservice.DescribeConfigRulesOutput, error) 14 | DescribeRemediationConfigurations(ctx context.Context, params *configservice.DescribeRemediationConfigurationsInput, optFns ...func(*configservice.Options)) (*configservice.DescribeRemediationConfigurationsOutput, error) 15 | DeleteRemediationConfiguration(ctx context.Context, params *configservice.DeleteRemediationConfigurationInput, optFns ...func(*configservice.Options)) (*configservice.DeleteRemediationConfigurationOutput, error) 16 | DeleteConfigRule(ctx context.Context, params *configservice.DeleteConfigRuleInput, optFns ...func(*configservice.Options)) (*configservice.DeleteConfigRuleOutput, error) 17 | } 18 | 19 | type ConfigServiceRule struct { 20 | BaseAwsResource 21 | Client ConfigServiceRuleAPI 22 | Region string 23 | RuleNames []string 24 | } 25 | 26 | func (csr *ConfigServiceRule) Init(cfg aws.Config) { 27 | csr.Client = configservice.NewFromConfig(cfg) 28 | } 29 | 30 | func (csr *ConfigServiceRule) ResourceName() string { 31 | return "config-rules" 32 | } 33 | 34 | func (csr *ConfigServiceRule) ResourceIdentifiers() []string { 35 | return csr.RuleNames 36 | } 37 | 38 | func (csr *ConfigServiceRule) MaxBatchSize() int { 39 | return 200 40 | } 41 | 42 | func (csr *ConfigServiceRule) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 43 | return configObj.ConfigServiceRule 44 | } 45 | 46 | func (csr *ConfigServiceRule) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := csr.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | csr.RuleNames = aws.ToStringSlice(identifiers) 53 | return csr.RuleNames, nil 54 | } 55 | 56 | func (csr *ConfigServiceRule) Nuke(identifiers []string) error { 57 | if err := csr.nukeAll(identifiers); err != nil { 58 | return errors.WithStackTrace(err) 59 | } 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /aws/resources/datasync_location_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/datasync" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type DataSyncLocationAPI interface { 13 | DeleteLocation(ctx context.Context, params *datasync.DeleteLocationInput, optFns ...func(*datasync.Options)) (*datasync.DeleteLocationOutput, error) 14 | ListLocations(ctx context.Context, params *datasync.ListLocationsInput, optFns ...func(*datasync.Options)) (*datasync.ListLocationsOutput, error) 15 | } 16 | 17 | type DataSyncLocation struct { 18 | BaseAwsResource 19 | Client DataSyncLocationAPI 20 | Region string 21 | DataSyncLocations []string 22 | } 23 | 24 | func (dsl *DataSyncLocation) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.DataSyncLocation 26 | } 27 | 28 | func (dsl *DataSyncLocation) Init(cfg aws.Config) { 29 | dsl.Client = datasync.NewFromConfig(cfg) 30 | } 31 | 32 | func (dsl *DataSyncLocation) ResourceName() string { return "data-sync-location" } 33 | 34 | func (dsl *DataSyncLocation) ResourceIdentifiers() []string { return dsl.DataSyncLocations } 35 | 36 | func (dsl *DataSyncLocation) MaxBatchSize() int { return 19 } 37 | 38 | func (dsl *DataSyncLocation) Nuke(identifiers []string) error { 39 | if err := dsl.nukeAll(aws.StringSlice(identifiers)); err != nil { 40 | return errors.WithStackTrace(err) 41 | } 42 | 43 | return nil 44 | } 45 | 46 | func (dsl *DataSyncLocation) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := dsl.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | dsl.DataSyncLocations = aws.ToStringSlice(identifiers) 53 | return dsl.DataSyncLocations, nil 54 | } 55 | -------------------------------------------------------------------------------- /aws/resources/datasync_task_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/datasync" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type DataSyncTaskAPI interface { 13 | DeleteTask(ctx context.Context, params *datasync.DeleteTaskInput, optFns ...func(*datasync.Options)) (*datasync.DeleteTaskOutput, error) 14 | ListTasks(ctx context.Context, params *datasync.ListTasksInput, optFns ...func(*datasync.Options)) (*datasync.ListTasksOutput, error) 15 | } 16 | 17 | type DataSyncTask struct { 18 | BaseAwsResource 19 | Client DataSyncTaskAPI 20 | Region string 21 | DataSyncTasks []string 22 | } 23 | 24 | func (dst *DataSyncTask) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.DataSyncTask 26 | } 27 | 28 | func (dst *DataSyncTask) Init(cfg aws.Config) { 29 | dst.Client = datasync.NewFromConfig(cfg) 30 | } 31 | 32 | func (dst *DataSyncTask) ResourceName() string { return "data-sync-task" } 33 | 34 | func (dst *DataSyncTask) ResourceIdentifiers() []string { return dst.DataSyncTasks } 35 | 36 | func (dst *DataSyncTask) MaxBatchSize() int { return 19 } 37 | 38 | func (dst *DataSyncTask) Nuke(identifiers []string) error { 39 | if err := dst.nukeAll(aws.StringSlice(identifiers)); err != nil { 40 | return errors.WithStackTrace(err) 41 | } 42 | 43 | return nil 44 | } 45 | 46 | func (dst *DataSyncTask) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := dst.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | dst.DataSyncTasks = aws.ToStringSlice(identifiers) 53 | return dst.DataSyncTasks, nil 54 | } 55 | -------------------------------------------------------------------------------- /aws/resources/dynamodb.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/aws/aws-sdk-go-v2/aws" 8 | "github.com/aws/aws-sdk-go-v2/service/dynamodb" 9 | "github.com/gruntwork-io/cloud-nuke/config" 10 | "github.com/gruntwork-io/cloud-nuke/logging" 11 | "github.com/gruntwork-io/cloud-nuke/report" 12 | "github.com/gruntwork-io/gruntwork-cli/errors" 13 | ) 14 | 15 | func (ddb *DynamoDB) getAll(c context.Context, configObj config.Config) ([]*string, error) { 16 | var tableNames []*string 17 | 18 | paginator := dynamodb.NewListTablesPaginator(ddb.Client, &dynamodb.ListTablesInput{}) 19 | for paginator.HasMorePages() { 20 | page, err := paginator.NextPage(c) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | for _, table := range page.TableNames { 26 | tableDetail, errPage := ddb.Client.DescribeTable(ddb.Context, &dynamodb.DescribeTableInput{TableName: aws.String(table)}) 27 | if errPage != nil { 28 | log.Fatalf("There was an error describing table: %v\n", errPage) 29 | } 30 | 31 | if configObj.DynamoDB.ShouldInclude(config.ResourceValue{ 32 | Time: tableDetail.Table.CreationDateTime, 33 | Name: tableDetail.Table.TableName, 34 | }) { 35 | tableNames = append(tableNames, aws.String(table)) 36 | } 37 | } 38 | } 39 | 40 | return tableNames, nil 41 | } 42 | 43 | func (ddb *DynamoDB) nukeAll(tables []*string) error { 44 | if len(tables) == 0 { 45 | logging.Debugf("No DynamoDB tables to nuke in region %s", ddb.Region) 46 | return nil 47 | } 48 | 49 | logging.Debugf("Deleting all DynamoDB tables in region %s", ddb.Region) 50 | for _, table := range tables { 51 | 52 | input := &dynamodb.DeleteTableInput{ 53 | TableName: aws.String(*table), 54 | } 55 | _, err := ddb.Client.DeleteTable(ddb.Context, input) 56 | 57 | // Record status of this resource 58 | e := report.Entry{ 59 | Identifier: aws.ToString(table), 60 | ResourceType: "DynamoDB Table", 61 | Error: err, 62 | } 63 | report.Record(e) 64 | 65 | if err != nil { 66 | return errors.WithStackTrace(err) 67 | } 68 | } 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /aws/resources/dynamodb_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/dynamodb" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/gruntwork-cli/errors" 10 | ) 11 | 12 | type DynamoDBAPI interface { 13 | ListTables(ctx context.Context, params *dynamodb.ListTablesInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListTablesOutput, error) 14 | DescribeTable(ctx context.Context, params *dynamodb.DescribeTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeTableOutput, error) 15 | DeleteTable(ctx context.Context, params *dynamodb.DeleteTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DeleteTableOutput, error) 16 | } 17 | 18 | type DynamoDB struct { 19 | BaseAwsResource 20 | Client DynamoDBAPI 21 | Region string 22 | DynamoTableNames []string 23 | } 24 | 25 | func (ddb *DynamoDB) Init(cfg aws.Config) { 26 | ddb.Client = dynamodb.NewFromConfig(cfg) 27 | } 28 | 29 | func (ddb *DynamoDB) ResourceName() string { 30 | return "dynamodb" 31 | } 32 | 33 | func (ddb *DynamoDB) ResourceIdentifiers() []string { 34 | return ddb.DynamoTableNames 35 | } 36 | 37 | func (ddb *DynamoDB) MaxBatchSize() int { 38 | // Tentative batch size to ensure AWS doesn't throttle 39 | return 49 40 | } 41 | 42 | func (ddb *DynamoDB) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 43 | return configObj.DynamoDB 44 | } 45 | 46 | func (ddb *DynamoDB) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := ddb.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | ddb.DynamoTableNames = aws.ToStringSlice(identifiers) 53 | return ddb.DynamoTableNames, nil 54 | } 55 | 56 | // Nuke - nuke all Dynamo DB Tables 57 | func (ddb *DynamoDB) Nuke(identifiers []string) error { 58 | if err := ddb.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /aws/resources/ebs_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EBSVolumesAPI interface { 13 | DescribeVolumes(ctx context.Context, params *ec2.DescribeVolumesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeVolumesOutput, error) 14 | DeleteVolume(ctx context.Context, params *ec2.DeleteVolumeInput, optFns ...func(*ec2.Options)) (*ec2.DeleteVolumeOutput, error) 15 | } 16 | 17 | // EBSVolumes - represents all ebs volumes 18 | type EBSVolumes struct { 19 | BaseAwsResource 20 | Client EBSVolumesAPI 21 | Region string 22 | VolumeIds []string 23 | } 24 | 25 | func (ev *EBSVolumes) Init(cfg aws.Config) { 26 | ev.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (ev *EBSVolumes) ResourceName() string { 31 | return "ebs" 32 | } 33 | 34 | // ResourceIdentifiers - The volume ids of the ebs volumes 35 | func (ev *EBSVolumes) ResourceIdentifiers() []string { 36 | return ev.VolumeIds 37 | } 38 | 39 | func (ev *EBSVolumes) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle 41 | return 49 42 | } 43 | 44 | func (ev *EBSVolumes) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.EBSVolume 46 | } 47 | 48 | func (ev *EBSVolumes) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := ev.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | ev.VolumeIds = aws.ToStringSlice(identifiers) 55 | return ev.VolumeIds, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (ev *EBSVolumes) Nuke(identifiers []string) error { 60 | if err := ev.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/ec2_dedicated_host_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2DedicatedHostsAPI interface { 13 | DescribeHosts(ctx context.Context, params *ec2.DescribeHostsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeHostsOutput, error) 14 | ReleaseHosts(ctx context.Context, params *ec2.ReleaseHostsInput, optFns ...func(*ec2.Options)) (*ec2.ReleaseHostsOutput, error) 15 | } 16 | 17 | // EC2DedicatedHosts - represents all host allocation IDs 18 | type EC2DedicatedHosts struct { 19 | BaseAwsResource 20 | Client EC2DedicatedHostsAPI 21 | Region string 22 | HostIds []string 23 | } 24 | 25 | func (h *EC2DedicatedHosts) Init(cfg aws.Config) { 26 | h.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (h *EC2DedicatedHosts) ResourceName() string { 31 | return "ec2-dedicated-hosts" 32 | } 33 | 34 | // ResourceIdentifiers - The instance ids of the ec2 instances 35 | func (h *EC2DedicatedHosts) ResourceIdentifiers() []string { 36 | return h.HostIds 37 | } 38 | 39 | func (h *EC2DedicatedHosts) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle 41 | return 49 42 | } 43 | 44 | func (h *EC2DedicatedHosts) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.EC2DedicatedHosts 46 | } 47 | 48 | func (h *EC2DedicatedHosts) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := h.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | h.HostIds = aws.ToStringSlice(identifiers) 55 | return h.HostIds, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (h *EC2DedicatedHosts) Nuke(identifiers []string) error { 60 | if err := h.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/ec2_dhcp_option_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type DHCPOption struct { 13 | Id *string 14 | VpcId *string 15 | } 16 | 17 | type EC2DhcpOptionAPI interface { 18 | AssociateDhcpOptions(ctx context.Context, params *ec2.AssociateDhcpOptionsInput, optFns ...func(*ec2.Options)) (*ec2.AssociateDhcpOptionsOutput, error) 19 | DescribeDhcpOptions(ctx context.Context, params *ec2.DescribeDhcpOptionsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeDhcpOptionsOutput, error) 20 | DescribeVpcs(ctx context.Context, params *ec2.DescribeVpcsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeVpcsOutput, error) 21 | DeleteDhcpOptions(ctx context.Context, params *ec2.DeleteDhcpOptionsInput, optFns ...func(*ec2.Options)) (*ec2.DeleteDhcpOptionsOutput, error) 22 | } 23 | 24 | type EC2DhcpOption struct { 25 | BaseAwsResource 26 | Client EC2DhcpOptionAPI 27 | Region string 28 | VPCIds []string 29 | DhcpOptions map[string]DHCPOption 30 | } 31 | 32 | func (v *EC2DhcpOption) Init(cfg aws.Config) { 33 | v.Client = ec2.NewFromConfig(cfg) 34 | v.DhcpOptions = make(map[string]DHCPOption) 35 | } 36 | 37 | // ResourceName - the simple name of the aws resource 38 | func (v *EC2DhcpOption) ResourceName() string { 39 | return "ec2_dhcp_option" 40 | } 41 | 42 | // ResourceIdentifiers - The instance ids of the ec2 instances 43 | func (v *EC2DhcpOption) ResourceIdentifiers() []string { 44 | return v.VPCIds 45 | } 46 | 47 | func (v *EC2DhcpOption) MaxBatchSize() int { 48 | // Tentative batch size to ensure AWS doesn't throttle 49 | return 49 50 | } 51 | 52 | func (v *EC2DhcpOption) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 53 | identifiers, err := v.getAll(c, configObj) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | v.VPCIds = aws.ToStringSlice(identifiers) 59 | return v.VPCIds, nil 60 | } 61 | 62 | func (v *EC2DhcpOption) Nuke(identifiers []string) error { 63 | if err := v.nukeAll(aws.StringSlice(identifiers)); err != nil { 64 | return errors.WithStackTrace(err) 65 | } 66 | 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /aws/resources/ec2_egress_only_igw_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EgressOnlyIGAPI interface { 13 | DescribeEgressOnlyInternetGateways(ctx context.Context, params *ec2.DescribeEgressOnlyInternetGatewaysInput, optFns ...func(*ec2.Options)) (*ec2.DescribeEgressOnlyInternetGatewaysOutput, error) 14 | DeleteEgressOnlyInternetGateway(ctx context.Context, params *ec2.DeleteEgressOnlyInternetGatewayInput, optFns ...func(*ec2.Options)) (*ec2.DeleteEgressOnlyInternetGatewayOutput, error) 15 | } 16 | 17 | // EgressOnlyInternetGateway represents all Egress only internet gateway 18 | type EgressOnlyInternetGateway struct { 19 | BaseAwsResource 20 | Client EgressOnlyIGAPI 21 | Region string 22 | Pools []string 23 | } 24 | 25 | func (egigw *EgressOnlyInternetGateway) Init(cfg aws.Config) { 26 | egigw.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (egigw *EgressOnlyInternetGateway) ResourceName() string { 31 | return "egress-only-internet-gateway" 32 | } 33 | 34 | func (egigw *EgressOnlyInternetGateway) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The ids of the Egress only igw 40 | func (egigw *EgressOnlyInternetGateway) ResourceIdentifiers() []string { 41 | return egigw.Pools 42 | } 43 | 44 | func (egigw *EgressOnlyInternetGateway) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.EgressOnlyInternetGateway 46 | } 47 | 48 | func (egigw *EgressOnlyInternetGateway) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := egigw.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | egigw.Pools = aws.ToStringSlice(identifiers) 55 | return egigw.Pools, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (egigw *EgressOnlyInternetGateway) Nuke(identifiers []string) error { 60 | if err := egigw.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/ec2_endpoints_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2EndpointsAPI interface { 13 | DescribeVpcEndpoints(ctx context.Context, params *ec2.DescribeVpcEndpointsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeVpcEndpointsOutput, error) 14 | DeleteVpcEndpoints(ctx context.Context, params *ec2.DeleteVpcEndpointsInput, optFns ...func(*ec2.Options)) (*ec2.DeleteVpcEndpointsOutput, error) 15 | } 16 | 17 | // EC2Endpoints - represents all ec2 endpoints 18 | type EC2Endpoints struct { 19 | BaseAwsResource 20 | Client EC2EndpointsAPI 21 | Region string 22 | Endpoints []string 23 | } 24 | 25 | func (e *EC2Endpoints) Init(cfg aws.Config) { 26 | e.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (e *EC2Endpoints) ResourceName() string { 31 | return "ec2-endpoint" 32 | } 33 | 34 | func (e *EC2Endpoints) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | func (e *EC2Endpoints) ResourceIdentifiers() []string { 40 | return e.Endpoints 41 | } 42 | 43 | func (e *EC2Endpoints) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 44 | return configObj.EC2Endpoint 45 | } 46 | 47 | func (e *EC2Endpoints) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 48 | identifiers, err := e.getAll(c, configObj) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | e.Endpoints = aws.ToStringSlice(identifiers) 54 | return e.Endpoints, nil 55 | } 56 | 57 | // Nuke - nuke 'em all!!! 58 | func (e *EC2Endpoints) Nuke(identifiers []string) error { 59 | if err := e.nukeAll(aws.StringSlice(identifiers)); err != nil { 60 | return errors.WithStackTrace(err) 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /aws/resources/ec2_ipam_byoasn_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2IPAMByoasnAPI interface { 13 | DescribeIpamByoasn(ctx context.Context, params *ec2.DescribeIpamByoasnInput, optFns ...func(*ec2.Options)) (*ec2.DescribeIpamByoasnOutput, error) 14 | DisassociateIpamByoasn(ctx context.Context, params *ec2.DisassociateIpamByoasnInput, optFns ...func(*ec2.Options)) (*ec2.DisassociateIpamByoasnOutput, error) 15 | } 16 | 17 | // EC2IPAMByoasn IPAM Byoasn- represents all IPAMs 18 | type EC2IPAMByoasn struct { 19 | BaseAwsResource 20 | Client EC2IPAMByoasnAPI 21 | Region string 22 | Pools []string 23 | } 24 | 25 | var MaxResultCount = int32(10) 26 | 27 | func (byoasn *EC2IPAMByoasn) Init(cfg aws.Config) { 28 | byoasn.Client = ec2.NewFromConfig(cfg) 29 | } 30 | 31 | // ResourceName - the simple name of the aws resource 32 | func (byoasn *EC2IPAMByoasn) ResourceName() string { 33 | return "ipam-byoasn" 34 | } 35 | 36 | func (byoasn *EC2IPAMByoasn) MaxBatchSize() int { 37 | // Tentative batch size to ensure AWS doesn't throttle 38 | return 49 39 | } 40 | 41 | // ResourceIdentifiers - The ids of the IPAMs 42 | func (byoasn *EC2IPAMByoasn) ResourceIdentifiers() []string { 43 | return byoasn.Pools 44 | } 45 | 46 | func (byoasn *EC2IPAMByoasn) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := byoasn.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | byoasn.Pools = aws.ToStringSlice(identifiers) 53 | return byoasn.Pools, nil 54 | } 55 | 56 | // Nuke - nuke 'em all!!! 57 | func (byoasn *EC2IPAMByoasn) Nuke(identifiers []string) error { 58 | if err := byoasn.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /aws/resources/ec2_ipam_custom_allocation_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2IPAMCustomAllocationAPI interface { 13 | DescribeIpamPools(ctx context.Context, params *ec2.DescribeIpamPoolsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeIpamPoolsOutput, error) 14 | GetIpamPoolAllocations(ctx context.Context, params *ec2.GetIpamPoolAllocationsInput, optFns ...func(*ec2.Options)) (*ec2.GetIpamPoolAllocationsOutput, error) 15 | ReleaseIpamPoolAllocation(ctx context.Context, params *ec2.ReleaseIpamPoolAllocationInput, optFns ...func(*ec2.Options)) (*ec2.ReleaseIpamPoolAllocationOutput, error) 16 | } 17 | 18 | // EC2IPAMCustomAllocation IPAM Byoasn- represents all IPAMs 19 | type EC2IPAMCustomAllocation struct { 20 | BaseAwsResource 21 | Client EC2IPAMCustomAllocationAPI 22 | Region string 23 | Allocations []string 24 | PoolAndAllocationMap map[string]string 25 | } 26 | 27 | func (cs *EC2IPAMCustomAllocation) Init(cfg aws.Config) { 28 | cs.Client = ec2.NewFromConfig(cfg) 29 | cs.PoolAndAllocationMap = make(map[string]string) 30 | } 31 | 32 | // ResourceName - the simple name of the aws resource 33 | func (cs *EC2IPAMCustomAllocation) ResourceName() string { 34 | return "ipam-custom-allocation" 35 | } 36 | 37 | func (cs *EC2IPAMCustomAllocation) MaxBatchSize() int { 38 | // Tentative batch size to ensure AWS doesn't throttle 39 | return 1000 40 | } 41 | 42 | // ResourceIdentifiers - The ids of the IPAMs 43 | func (cs *EC2IPAMCustomAllocation) ResourceIdentifiers() []string { 44 | return cs.Allocations 45 | } 46 | 47 | func (cs *EC2IPAMCustomAllocation) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 48 | identifiers, err := cs.getAll(c, configObj) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | cs.Allocations = aws.ToStringSlice(identifiers) 54 | return cs.Allocations, nil 55 | } 56 | 57 | // Nuke - nuke 'em all!!! 58 | func (cs *EC2IPAMCustomAllocation) Nuke(identifiers []string) error { 59 | if err := cs.nukeAll(aws.StringSlice(identifiers)); err != nil { 60 | return errors.WithStackTrace(err) 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /aws/resources/ec2_ipam_pool_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2IPAMPoolAPI interface { 13 | DescribeIpamPools(ctx context.Context, params *ec2.DescribeIpamPoolsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeIpamPoolsOutput, error) 14 | DeleteIpamPool(ctx context.Context, params *ec2.DeleteIpamPoolInput, optFns ...func(*ec2.Options)) (*ec2.DeleteIpamPoolOutput, error) 15 | } 16 | 17 | // EC2IPAMPool IPAM Pool- represents all IPAMs 18 | type EC2IPAMPool struct { 19 | BaseAwsResource 20 | Client EC2IPAMPoolAPI 21 | Region string 22 | Pools []string 23 | } 24 | 25 | func (pool *EC2IPAMPool) Init(cfg aws.Config) { 26 | pool.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (pool *EC2IPAMPool) ResourceName() string { 31 | return "ipam-pool" 32 | } 33 | 34 | func (pool *EC2IPAMPool) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The ids of the IPAMs 40 | func (pool *EC2IPAMPool) ResourceIdentifiers() []string { 41 | return pool.Pools 42 | } 43 | 44 | func (pool *EC2IPAMPool) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.EC2IPAMPool 46 | } 47 | 48 | func (pool *EC2IPAMPool) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := pool.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | pool.Pools = aws.ToStringSlice(identifiers) 55 | return pool.Pools, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (pool *EC2IPAMPool) Nuke(identifiers []string) error { 60 | if err := pool.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/ec2_ipam_resource_discovery_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2IPAMResourceDiscoveryAPI interface { 13 | DescribeIpamResourceDiscoveries(ctx context.Context, params *ec2.DescribeIpamResourceDiscoveriesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeIpamResourceDiscoveriesOutput, error) 14 | DeleteIpamResourceDiscovery(ctx context.Context, params *ec2.DeleteIpamResourceDiscoveryInput, optFns ...func(*ec2.Options)) (*ec2.DeleteIpamResourceDiscoveryOutput, error) 15 | } 16 | 17 | // EC2IPAMResourceDiscovery IPAM - represents all IPAMs 18 | type EC2IPAMResourceDiscovery struct { 19 | BaseAwsResource 20 | Client EC2IPAMResourceDiscoveryAPI 21 | Region string 22 | DiscoveryIDs []string 23 | } 24 | 25 | func (ipam *EC2IPAMResourceDiscovery) Init(cfg aws.Config) { 26 | ipam.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (ipam *EC2IPAMResourceDiscovery) ResourceName() string { 31 | return "ipam-resource-discovery" 32 | } 33 | 34 | func (ipam *EC2IPAMResourceDiscovery) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The ids of the IPAMs 40 | func (ipam *EC2IPAMResourceDiscovery) ResourceIdentifiers() []string { 41 | return ipam.DiscoveryIDs 42 | } 43 | 44 | func (ipam *EC2IPAMResourceDiscovery) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.EC2IPAMResourceDiscovery 46 | } 47 | 48 | func (ipam *EC2IPAMResourceDiscovery) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := ipam.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | ipam.DiscoveryIDs = aws.ToStringSlice(identifiers) 55 | return ipam.DiscoveryIDs, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (ipam *EC2IPAMResourceDiscovery) Nuke(identifiers []string) error { 60 | if err := ipam.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/ec2_ipam_scope_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2IpamScopesAPI interface { 13 | DescribeIpamScopes(ctx context.Context, params *ec2.DescribeIpamScopesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeIpamScopesOutput, error) 14 | DeleteIpamScope(ctx context.Context, params *ec2.DeleteIpamScopeInput, optFns ...func(*ec2.Options)) (*ec2.DeleteIpamScopeOutput, error) 15 | } 16 | 17 | // EC2IpamScopes scope - represents all scopes 18 | type EC2IpamScopes struct { 19 | BaseAwsResource 20 | Client EC2IpamScopesAPI 21 | Region string 22 | ScopreIDs []string 23 | } 24 | 25 | func (scope *EC2IpamScopes) Init(cfg aws.Config) { 26 | scope.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (scope *EC2IpamScopes) ResourceName() string { 31 | return "ipam-scope" 32 | } 33 | 34 | func (scope *EC2IpamScopes) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The ids of the scopes 40 | func (scope *EC2IpamScopes) ResourceIdentifiers() []string { 41 | return scope.ScopreIDs 42 | } 43 | 44 | func (scope *EC2IpamScopes) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.EC2IPAMScope 46 | } 47 | 48 | func (scope *EC2IpamScopes) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := scope.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | scope.ScopreIDs = aws.ToStringSlice(identifiers) 55 | return scope.ScopreIDs, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (scope *EC2IpamScopes) Nuke(identifiers []string) error { 60 | if err := scope.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/ec2_key_pair_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2KeyPairsAPI interface { 13 | DeleteKeyPair(ctx context.Context, params *ec2.DeleteKeyPairInput, optFns ...func(*ec2.Options)) (*ec2.DeleteKeyPairOutput, error) 14 | DescribeKeyPairs(ctx context.Context, params *ec2.DescribeKeyPairsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeKeyPairsOutput, error) 15 | } 16 | 17 | type EC2KeyPairs struct { 18 | BaseAwsResource 19 | Client EC2KeyPairsAPI 20 | Region string 21 | KeyPairIds []string 22 | } 23 | 24 | func (k *EC2KeyPairs) Init(cfg aws.Config) { 25 | k.Client = ec2.NewFromConfig(cfg) 26 | } 27 | 28 | // ResourceName - the simple name of the aws resource 29 | func (k *EC2KeyPairs) ResourceName() string { 30 | return "ec2-keypairs" 31 | } 32 | 33 | // ResourceIdentifiers - IDs of the ec2 key pairs 34 | func (k *EC2KeyPairs) ResourceIdentifiers() []string { 35 | return k.KeyPairIds 36 | } 37 | 38 | func (k *EC2KeyPairs) MaxBatchSize() int { 39 | // Tentative batch size to ensure AWS doesn't throttle 40 | return 200 41 | } 42 | 43 | func (k *EC2KeyPairs) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 44 | return configObj.EC2KeyPairs 45 | } 46 | 47 | func (k *EC2KeyPairs) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 48 | identifiers, err := k.getAll(c, configObj) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | k.KeyPairIds = aws.ToStringSlice(identifiers) 54 | return k.KeyPairIds, nil 55 | } 56 | 57 | func (k *EC2KeyPairs) Nuke(identifiers []string) error { 58 | if err := k.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /aws/resources/ec2_network_acl_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type NetworkACLAPI interface { 13 | DescribeNetworkAcls(ctx context.Context, params *ec2.DescribeNetworkAclsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeNetworkAclsOutput, error) 14 | DeleteNetworkAcl(ctx context.Context, params *ec2.DeleteNetworkAclInput, optFns ...func(*ec2.Options)) (*ec2.DeleteNetworkAclOutput, error) 15 | ReplaceNetworkAclAssociation(ctx context.Context, params *ec2.ReplaceNetworkAclAssociationInput, optFns ...func(*ec2.Options)) (*ec2.ReplaceNetworkAclAssociationOutput, error) // Add this line 16 | } 17 | 18 | type NetworkACL struct { 19 | BaseAwsResource 20 | Client NetworkACLAPI 21 | Region string 22 | Ids []string 23 | } 24 | 25 | func (nacl *NetworkACL) Init(cfg aws.Config) { 26 | nacl.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | func (nacl *NetworkACL) ResourceName() string { 30 | return "network-acl" 31 | } 32 | 33 | func (nacl *NetworkACL) ResourceIdentifiers() []string { 34 | return nacl.Ids 35 | } 36 | 37 | func (nacl *NetworkACL) MaxBatchSize() int { 38 | return 50 39 | } 40 | 41 | func (nacl *NetworkACL) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 42 | return configObj.NetworkACL 43 | } 44 | 45 | func (nacl *NetworkACL) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := nacl.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | nacl.Ids = aws.ToStringSlice(identifiers) 52 | return nacl.Ids, nil 53 | } 54 | 55 | func (nacl *NetworkACL) Nuke(identifiers []string) error { 56 | if err := nacl.nukeAll(aws.StringSlice(identifiers)); err != nil { 57 | return errors.WithStackTrace(err) 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /aws/resources/ec2_placement_group_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2PlacementGroupsAPI interface { 13 | DescribePlacementGroups(ctx context.Context, params *ec2.DescribePlacementGroupsInput, optFns ...func(*ec2.Options)) (*ec2.DescribePlacementGroupsOutput, error) 14 | DeletePlacementGroup(ctx context.Context, params *ec2.DeletePlacementGroupInput, optFns ...func(*ec2.Options)) (*ec2.DeletePlacementGroupOutput, error) 15 | } 16 | 17 | type EC2PlacementGroups struct { 18 | BaseAwsResource 19 | Client EC2PlacementGroupsAPI 20 | Region string 21 | PlacementGroupNames []string 22 | } 23 | 24 | func (k *EC2PlacementGroups) Init(cfg aws.Config) { 25 | k.Client = ec2.NewFromConfig(cfg) 26 | } 27 | 28 | // ResourceName - the simple name of the aws resource 29 | func (k *EC2PlacementGroups) ResourceName() string { 30 | return "ec2-placement-groups" 31 | } 32 | 33 | // ResourceIdentifiers - IDs of the ec2 key pairs 34 | func (k *EC2PlacementGroups) ResourceIdentifiers() []string { 35 | return k.PlacementGroupNames 36 | } 37 | 38 | func (k *EC2PlacementGroups) MaxBatchSize() int { 39 | // Tentative batch size to ensure AWS doesn't throttle 40 | return 200 41 | } 42 | 43 | func (k *EC2PlacementGroups) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 44 | return configObj.EC2PlacementGroups 45 | } 46 | 47 | func (k *EC2PlacementGroups) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 48 | identifiers, err := k.getAll(c, configObj) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | k.PlacementGroupNames = aws.ToStringSlice(identifiers) 54 | return k.PlacementGroupNames, nil 55 | } 56 | 57 | func (k *EC2PlacementGroups) Nuke(identifiers []string) error { 58 | if err := k.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /aws/resources/ec2_subnet_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EC2SubnetAPI interface { 13 | DeleteSubnet(ctx context.Context, params *ec2.DeleteSubnetInput, optFns ...func(*ec2.Options)) (*ec2.DeleteSubnetOutput, error) 14 | DescribeSubnets(ctx context.Context, params *ec2.DescribeSubnetsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeSubnetsOutput, error) 15 | } 16 | 17 | // Ec2Subnet- represents all Subnets 18 | type EC2Subnet struct { 19 | BaseAwsResource 20 | Client EC2SubnetAPI 21 | Region string 22 | Subnets []string 23 | } 24 | 25 | func (es *EC2Subnet) Init(cfg aws.Config) { 26 | es.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (es *EC2Subnet) ResourceName() string { 31 | return "ec2-subnet" 32 | } 33 | 34 | func (es *EC2Subnet) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The ids of the subnets 40 | func (es *EC2Subnet) ResourceIdentifiers() []string { 41 | return es.Subnets 42 | } 43 | 44 | func (es *EC2Subnet) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := es.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | es.Subnets = aws.ToStringSlice(identifiers) 51 | return es.Subnets, nil 52 | } 53 | 54 | // Nuke - nuke 'em all!!! 55 | func (es *EC2Subnet) Nuke(identifiers []string) error { 56 | if err := es.nukeAll(aws.StringSlice(identifiers)); err != nil { 57 | return errors.WithStackTrace(err) 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /aws/resources/ecr.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ecr" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | func (registry *ECR) getAll(c context.Context, configObj config.Config) ([]*string, error) { 15 | var repositoryNames []*string 16 | 17 | paginator := ecr.NewDescribeRepositoriesPaginator(registry.Client, &ecr.DescribeRepositoriesInput{}) 18 | for paginator.HasMorePages() { 19 | output, err := paginator.NextPage(c) 20 | if err != nil { 21 | return nil, errors.WithStackTrace(err) 22 | } 23 | 24 | for _, repository := range output.Repositories { 25 | if configObj.ECRRepository.ShouldInclude(config.ResourceValue{ 26 | Time: repository.CreatedAt, 27 | Name: repository.RepositoryName, 28 | }) { 29 | repositoryNames = append(repositoryNames, repository.RepositoryName) 30 | } 31 | } 32 | } 33 | 34 | return repositoryNames, nil 35 | } 36 | 37 | func (registry *ECR) nukeAll(repositoryNames []string) error { 38 | if len(repositoryNames) == 0 { 39 | logging.Debugf("No ECR repositories to nuke in region %s", registry.Region) 40 | return nil 41 | } 42 | 43 | var deletedNames []*string 44 | 45 | for _, repositoryName := range repositoryNames { 46 | params := &ecr.DeleteRepositoryInput{ 47 | Force: true, 48 | RepositoryName: aws.String(repositoryName), 49 | } 50 | 51 | _, err := registry.Client.DeleteRepository(registry.Context, params) 52 | 53 | // Record status of this resource 54 | e := report.Entry{ 55 | Identifier: repositoryName, 56 | ResourceType: "ECR Repository", 57 | Error: err, 58 | } 59 | report.Record(e) 60 | 61 | if err != nil { 62 | logging.Debugf("[Failed] %s", err) 63 | } else { 64 | 65 | deletedNames = append(deletedNames, aws.String(repositoryName)) 66 | logging.Debugf("Deleted ECR Repository: %s", repositoryName) 67 | } 68 | } 69 | 70 | logging.Debugf("[OK] %d ECR Repositories deleted in %s", len(deletedNames), registry.Region) 71 | 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /aws/resources/ecr_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ecr" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type ECRAPI interface { 13 | DescribeRepositories(ctx context.Context, params *ecr.DescribeRepositoriesInput, optFns ...func(*ecr.Options)) (*ecr.DescribeRepositoriesOutput, error) 14 | DeleteRepository(ctx context.Context, params *ecr.DeleteRepositoryInput, optFns ...func(*ecr.Options)) (*ecr.DeleteRepositoryOutput, error) 15 | } 16 | 17 | type ECR struct { 18 | BaseAwsResource 19 | Client ECRAPI 20 | Region string 21 | RepositoryNames []string 22 | } 23 | 24 | func (registry *ECR) Init(cfg aws.Config) { 25 | registry.Client = ecr.NewFromConfig(cfg) 26 | } 27 | 28 | func (registry *ECR) ResourceName() string { 29 | return "ecr" 30 | } 31 | 32 | func (registry *ECR) ResourceIdentifiers() []string { 33 | return registry.RepositoryNames 34 | } 35 | 36 | func (registry *ECR) MaxBatchSize() int { 37 | return 50 38 | } 39 | 40 | func (registry *ECR) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 41 | return configObj.ECRRepository 42 | } 43 | 44 | func (registry *ECR) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := registry.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | registry.RepositoryNames = aws.ToStringSlice(identifiers) 51 | return registry.RepositoryNames, nil 52 | } 53 | 54 | func (registry *ECR) Nuke(identifiers []string) error { 55 | if err := registry.nukeAll(identifiers); err != nil { 56 | return errors.WithStackTrace(err) 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /aws/resources/eip_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EIPAddressesAPI interface { 13 | ReleaseAddress(ctx context.Context, params *ec2.ReleaseAddressInput, optFns ...func(*ec2.Options)) (*ec2.ReleaseAddressOutput, error) 14 | DescribeAddresses(ctx context.Context, params *ec2.DescribeAddressesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeAddressesOutput, error) 15 | } 16 | 17 | // EIPAddresses - represents all ebs volumes 18 | type EIPAddresses struct { 19 | BaseAwsResource 20 | Client EIPAddressesAPI 21 | Region string 22 | AllocationIds []string 23 | } 24 | 25 | func (eip *EIPAddresses) Init(cfg aws.Config) { 26 | eip.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (eip *EIPAddresses) ResourceName() string { 31 | return "eip" 32 | } 33 | 34 | // ResourceIdentifiers - The instance ids of the eip addresses 35 | func (eip *EIPAddresses) ResourceIdentifiers() []string { 36 | return eip.AllocationIds 37 | } 38 | 39 | func (eip *EIPAddresses) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle 41 | return 49 42 | } 43 | 44 | func (eip *EIPAddresses) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.ElasticIP 46 | } 47 | 48 | func (eip *EIPAddresses) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := eip.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | eip.AllocationIds = aws.ToStringSlice(identifiers) 55 | return eip.AllocationIds, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (eip *EIPAddresses) Nuke(identifiers []string) error { 60 | if err := eip.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/elastic_beanstalk_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EBApplicationsAPI interface { 13 | DescribeApplications(ctx context.Context, params *elasticbeanstalk.DescribeApplicationsInput, optFns ...func(*elasticbeanstalk.Options)) (*elasticbeanstalk.DescribeApplicationsOutput, error) 14 | DeleteApplication(ctx context.Context, params *elasticbeanstalk.DeleteApplicationInput, optFns ...func(*elasticbeanstalk.Options)) (*elasticbeanstalk.DeleteApplicationOutput, error) 15 | } 16 | 17 | // EBApplications - represents all elastic beanstalk applications 18 | type EBApplications struct { 19 | BaseAwsResource 20 | Client EBApplicationsAPI 21 | Region string 22 | appIds []string 23 | } 24 | 25 | func (eb *EBApplications) Init(cfg aws.Config) { 26 | eb.Client = elasticbeanstalk.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (eb *EBApplications) ResourceName() string { 31 | return "elastic-beanstalk" 32 | } 33 | 34 | // ResourceIdentifiers - The application ids of the elastic beanstalk 35 | func (eb *EBApplications) ResourceIdentifiers() []string { 36 | return eb.appIds 37 | } 38 | 39 | func (eb *EBApplications) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle 41 | return 49 42 | } 43 | 44 | func (eb *EBApplications) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.ElasticBeanstalk 46 | } 47 | 48 | func (eb *EBApplications) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := eb.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | eb.appIds = aws.ToStringSlice(identifiers) 55 | return eb.appIds, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (eb *EBApplications) Nuke(identifiers []string) error { 60 | if err := eb.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/elasticache_serverless_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/elasticache" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type ElasticCacheServerlessAPI interface { 13 | DeleteServerlessCache(ctx context.Context, params *elasticache.DeleteServerlessCacheInput, optFns ...func(*elasticache.Options)) (*elasticache.DeleteServerlessCacheOutput, error) 14 | DescribeServerlessCaches(ctx context.Context, params *elasticache.DescribeServerlessCachesInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeServerlessCachesOutput, error) 15 | } 16 | 17 | type ElasticCacheServerless struct { 18 | BaseAwsResource 19 | Client ElasticCacheServerlessAPI 20 | Region string 21 | ClusterIds []string 22 | } 23 | 24 | func (cache *ElasticCacheServerless) Init(cfg aws.Config) { 25 | cache.Client = elasticache.NewFromConfig(cfg) 26 | } 27 | 28 | func (cache *ElasticCacheServerless) ResourceName() string { 29 | return "elasticcache-serverless" 30 | } 31 | 32 | func (cache *ElasticCacheServerless) ResourceIdentifiers() []string { 33 | return cache.ClusterIds 34 | } 35 | 36 | func (cache *ElasticCacheServerless) MaxBatchSize() int { 37 | // Tentative batch size to ensure AWS doesn't throttle 38 | return 49 39 | } 40 | 41 | func (cache *ElasticCacheServerless) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 42 | return configObj.Elasticache 43 | } 44 | 45 | func (cache *ElasticCacheServerless) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := cache.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | cache.ClusterIds = aws.ToStringSlice(identifiers) 52 | return cache.ClusterIds, nil 53 | } 54 | 55 | func (cache *ElasticCacheServerless) Nuke(identifiers []string) error { 56 | if err := cache.nukeAll(aws.StringSlice(identifiers)); err != nil { 57 | return errors.WithStackTrace(err) 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /aws/resources/elb_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type LoadBalancersAPI interface { 13 | DescribeLoadBalancers(ctx context.Context, params *elasticloadbalancing.DescribeLoadBalancersInput, optFns ...func(*elasticloadbalancing.Options)) (*elasticloadbalancing.DescribeLoadBalancersOutput, error) 14 | DeleteLoadBalancer(ctx context.Context, params *elasticloadbalancing.DeleteLoadBalancerInput, optFns ...func(*elasticloadbalancing.Options)) (*elasticloadbalancing.DeleteLoadBalancerOutput, error) 15 | } 16 | 17 | // LoadBalancers - represents all load balancers 18 | type LoadBalancers struct { 19 | BaseAwsResource 20 | Client LoadBalancersAPI 21 | Region string 22 | Names []string 23 | } 24 | 25 | func (balancer *LoadBalancers) Init(cfg aws.Config) { 26 | balancer.Client = elasticloadbalancing.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (balancer *LoadBalancers) ResourceName() string { 31 | return "elb" 32 | } 33 | 34 | // ResourceIdentifiers - The names of the load balancers 35 | func (balancer *LoadBalancers) ResourceIdentifiers() []string { 36 | return balancer.Names 37 | } 38 | 39 | func (balancer *LoadBalancers) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle 41 | return 49 42 | } 43 | 44 | func (balancer *LoadBalancers) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.ELBv1 46 | } 47 | 48 | func (balancer *LoadBalancers) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := balancer.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | balancer.Names = aws.ToStringSlice(identifiers) 55 | return balancer.Names, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (balancer *LoadBalancers) Nuke(identifiers []string) error { 60 | if err := balancer.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | 67 | type ElbDeleteError struct{} 68 | 69 | func (e ElbDeleteError) Error() string { 70 | return "ELB was not deleted" 71 | } 72 | -------------------------------------------------------------------------------- /aws/resources/elbv2_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type LoadBalancersV2API interface { 13 | DescribeLoadBalancers(ctx context.Context, params *elasticloadbalancingv2.DescribeLoadBalancersInput, optFns ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DescribeLoadBalancersOutput, error) 14 | DeleteLoadBalancer(ctx context.Context, params *elasticloadbalancingv2.DeleteLoadBalancerInput, optFns ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DeleteLoadBalancerOutput, error) 15 | } 16 | 17 | // LoadBalancersV2 - represents all load balancers 18 | type LoadBalancersV2 struct { 19 | BaseAwsResource 20 | Client LoadBalancersV2API 21 | Region string 22 | Arns []string 23 | } 24 | 25 | func (balancer *LoadBalancersV2) Init(cfg aws.Config) { 26 | balancer.Client = elasticloadbalancingv2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (balancer *LoadBalancersV2) ResourceName() string { 31 | return "elbv2" 32 | } 33 | 34 | func (balancer *LoadBalancersV2) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The arns of the load balancers 40 | func (balancer *LoadBalancersV2) ResourceIdentifiers() []string { 41 | return balancer.Arns 42 | } 43 | 44 | func (balancer *LoadBalancersV2) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.ELBv2 46 | } 47 | 48 | func (balancer *LoadBalancersV2) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := balancer.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | balancer.Arns = aws.ToStringSlice(identifiers) 55 | return balancer.Arns, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (balancer *LoadBalancersV2) Nuke(identifiers []string) error { 60 | if err := balancer.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/eventbridge_archive_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/eventbridge" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EventBridgeArchiveAPI interface { 13 | ListArchives(ctx context.Context, params *eventbridge.ListArchivesInput, optFns ...func(*eventbridge.Options)) (*eventbridge.ListArchivesOutput, error) 14 | DeleteArchive(ctx context.Context, params *eventbridge.DeleteArchiveInput, optFns ...func(*eventbridge.Options)) (*eventbridge.DeleteArchiveOutput, error) 15 | } 16 | 17 | type EventBridgeArchive struct { 18 | BaseAwsResource 19 | Client EventBridgeArchiveAPI 20 | Region string 21 | Rules []string 22 | } 23 | 24 | func (eba *EventBridgeArchive) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.EventBridgeArchive 26 | } 27 | 28 | func (eba *EventBridgeArchive) Init(cfg aws.Config) { 29 | eba.Client = eventbridge.NewFromConfig(cfg) 30 | } 31 | 32 | func (eba *EventBridgeArchive) ResourceName() string { return "event-bridge-archive" } 33 | 34 | func (eba *EventBridgeArchive) ResourceIdentifiers() []string { return eba.Rules } 35 | 36 | func (eba *EventBridgeArchive) MaxBatchSize() int { 37 | return 100 38 | } 39 | 40 | func (eba *EventBridgeArchive) Nuke(identifiers []string) error { 41 | if err := eba.nukeAll(aws.StringSlice(identifiers)); err != nil { 42 | return errors.WithStackTrace(err) 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (eba *EventBridgeArchive) GetAndSetIdentifiers(ctx context.Context, cnfObj config.Config) ([]string, error) { 49 | identifiers, err := eba.getAll(ctx, cnfObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | eba.Rules = aws.ToStringSlice(identifiers) 55 | return eba.Rules, nil 56 | } 57 | -------------------------------------------------------------------------------- /aws/resources/eventbridge_rule_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/eventbridge" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EventBridgeRuleAPI interface { 13 | ListRules(ctx context.Context, params *eventbridge.ListRulesInput, optFns ...func(*eventbridge.Options)) (*eventbridge.ListRulesOutput, error) 14 | DeleteRule(ctx context.Context, params *eventbridge.DeleteRuleInput, optFns ...func(*eventbridge.Options)) (*eventbridge.DeleteRuleOutput, error) 15 | ListEventBuses(ctx context.Context, params *eventbridge.ListEventBusesInput, optFns ...func(*eventbridge.Options)) (*eventbridge.ListEventBusesOutput, error) 16 | ListTargetsByRule(ctx context.Context, params *eventbridge.ListTargetsByRuleInput, optFns ...func(*eventbridge.Options)) (*eventbridge.ListTargetsByRuleOutput, error) 17 | RemoveTargets(ctx context.Context, params *eventbridge.RemoveTargetsInput, optFns ...func(*eventbridge.Options)) (*eventbridge.RemoveTargetsOutput, error) 18 | } 19 | 20 | type EventBridgeRule struct { 21 | BaseAwsResource 22 | Client EventBridgeRuleAPI 23 | Region string 24 | Rules []string 25 | } 26 | 27 | func (ebr *EventBridgeRule) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 28 | return configObj.EventBridgeRule 29 | } 30 | 31 | func (ebr *EventBridgeRule) Init(cfg aws.Config) { 32 | ebr.Client = eventbridge.NewFromConfig(cfg) 33 | } 34 | 35 | func (ebr *EventBridgeRule) ResourceName() string { return "event-bridge-rule" } 36 | 37 | func (ebr *EventBridgeRule) ResourceIdentifiers() []string { return ebr.Rules } 38 | 39 | func (ebr *EventBridgeRule) MaxBatchSize() int { 40 | return 100 41 | } 42 | 43 | func (ebr *EventBridgeRule) Nuke(identifiers []string) error { 44 | if err := ebr.nukeAll(aws.StringSlice(identifiers)); err != nil { 45 | return errors.WithStackTrace(err) 46 | } 47 | 48 | return nil 49 | } 50 | 51 | func (ebr *EventBridgeRule) GetAndSetIdentifiers(ctx context.Context, cnfObj config.Config) ([]string, error) { 52 | identifiers, err := ebr.getAll(ctx, cnfObj) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | ebr.Rules = aws.ToStringSlice(identifiers) 58 | return ebr.Rules, nil 59 | } 60 | -------------------------------------------------------------------------------- /aws/resources/eventbridge_schedule_group_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/scheduler" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EventBridgeScheduleGroupAPI interface { 13 | DeleteScheduleGroup(ctx context.Context, params *scheduler.DeleteScheduleGroupInput, optFns ...func(*scheduler.Options)) (*scheduler.DeleteScheduleGroupOutput, error) 14 | ListScheduleGroups(ctx context.Context, params *scheduler.ListScheduleGroupsInput, optFns ...func(*scheduler.Options)) (*scheduler.ListScheduleGroupsOutput, error) 15 | } 16 | 17 | type EventBridgeScheduleGroup struct { 18 | BaseAwsResource 19 | Client EventBridgeScheduleGroupAPI 20 | Region string 21 | Groups []string 22 | } 23 | 24 | func (sch *EventBridgeScheduleGroup) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.EventBridgeScheduleGroup 26 | } 27 | 28 | func (sch *EventBridgeScheduleGroup) Init(cfg aws.Config) { 29 | sch.Client = scheduler.NewFromConfig(cfg) 30 | } 31 | 32 | func (sch *EventBridgeScheduleGroup) ResourceName() string { return "event-bridge-schedule-group" } 33 | 34 | func (sch *EventBridgeScheduleGroup) ResourceIdentifiers() []string { return sch.Groups } 35 | 36 | func (sch *EventBridgeScheduleGroup) MaxBatchSize() int { 37 | return 100 38 | } 39 | 40 | func (sch *EventBridgeScheduleGroup) Nuke(identifiers []string) error { 41 | if err := sch.nukeAll(aws.StringSlice(identifiers)); err != nil { 42 | return errors.WithStackTrace(err) 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (sch *EventBridgeScheduleGroup) GetAndSetIdentifiers(ctx context.Context, cnfObj config.Config) ([]string, error) { 49 | identifiers, err := sch.getAll(ctx, cnfObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | sch.Groups = aws.ToStringSlice(identifiers) 55 | return sch.Groups, nil 56 | } 57 | -------------------------------------------------------------------------------- /aws/resources/eventbridge_schedule_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/scheduler" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EventBridgeScheduleAPI interface { 13 | DeleteSchedule(ctx context.Context, params *scheduler.DeleteScheduleInput, optFns ...func(*scheduler.Options)) (*scheduler.DeleteScheduleOutput, error) 14 | ListSchedules(ctx context.Context, params *scheduler.ListSchedulesInput, optFns ...func(*scheduler.Options)) (*scheduler.ListSchedulesOutput, error) 15 | } 16 | 17 | type EventBridgeSchedule struct { 18 | BaseAwsResource 19 | Client EventBridgeScheduleAPI 20 | Region string 21 | Schedules []string 22 | } 23 | 24 | func (sch *EventBridgeSchedule) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.EventBridgeSchedule 26 | } 27 | 28 | func (sch *EventBridgeSchedule) Init(cfg aws.Config) { 29 | sch.Client = scheduler.NewFromConfig(cfg) 30 | } 31 | 32 | func (sch *EventBridgeSchedule) ResourceName() string { return "event-bridge-schedule" } 33 | 34 | func (sch *EventBridgeSchedule) ResourceIdentifiers() []string { return sch.Schedules } 35 | 36 | func (sch *EventBridgeSchedule) MaxBatchSize() int { 37 | return 100 38 | } 39 | 40 | func (sch *EventBridgeSchedule) Nuke(identifiers []string) error { 41 | if err := sch.nukeAll(aws.StringSlice(identifiers)); err != nil { 42 | return errors.WithStackTrace(err) 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (sch *EventBridgeSchedule) GetAndSetIdentifiers(ctx context.Context, cnfObj config.Config) ([]string, error) { 49 | identifiers, err := sch.getAll(ctx, cnfObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | sch.Schedules = aws.ToStringSlice(identifiers) 55 | return sch.Schedules, nil 56 | } 57 | -------------------------------------------------------------------------------- /aws/resources/eventbridge_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/eventbridge" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type EventBridgeAPI interface { 13 | DeleteEventBus(ctx context.Context, params *eventbridge.DeleteEventBusInput, optFns ...func(*eventbridge.Options)) (*eventbridge.DeleteEventBusOutput, error) 14 | ListEventBuses(ctx context.Context, params *eventbridge.ListEventBusesInput, optFns ...func(*eventbridge.Options)) (*eventbridge.ListEventBusesOutput, error) 15 | } 16 | 17 | type EventBridge struct { 18 | BaseAwsResource 19 | Client EventBridgeAPI 20 | Region string 21 | EventBuses []string 22 | } 23 | 24 | func (eb *EventBridge) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.EventBridge 26 | } 27 | 28 | func (eb *EventBridge) Init(cfg aws.Config) { 29 | eb.Client = eventbridge.NewFromConfig(cfg) 30 | } 31 | 32 | func (eb *EventBridge) ResourceName() string { return "event-bridge" } 33 | 34 | func (eb *EventBridge) ResourceIdentifiers() []string { return eb.EventBuses } 35 | 36 | func (eb *EventBridge) MaxBatchSize() int { 37 | return 100 38 | } 39 | 40 | func (eb *EventBridge) Nuke(identifiers []string) error { 41 | if err := eb.nukeAll(aws.StringSlice(identifiers)); err != nil { 42 | return errors.WithStackTrace(err) 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (eb *EventBridge) GetAndSetIdentifiers(ctx context.Context, cnfObj config.Config) ([]string, error) { 49 | identifiers, err := eb.getAll(ctx, cnfObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | eb.EventBuses = aws.ToStringSlice(identifiers) 55 | return eb.EventBuses, nil 56 | } 57 | -------------------------------------------------------------------------------- /aws/resources/globals.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import "time" 4 | 5 | const ( 6 | // A tag used to set custom AWS Tags to resources that do not support `created at` timestamp> - EIP & ECS Clusters. 7 | // This is used in relation to the `--older-than ` filtering that `cloud-nuke` allows. 8 | // Due to its destructive nature, `cloud-nuke` has been configured not to delete AWS resources without known creation time, 9 | // and instead tag them with the `firstSeenTagKey`. 10 | // The next time `cloud-nuke aws --older-than ` is run, it will use the tag to determine if the AWS resource should be deleted or not. 11 | firstSeenTagKey = "cloud-nuke-first-seen" 12 | 13 | // The time format of the `firstSeenTagKey` tag value. 14 | firstSeenTimeFormat = time.RFC3339 15 | ) 16 | -------------------------------------------------------------------------------- /aws/resources/grafana_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/grafana" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type GrafanaAPI interface { 13 | DeleteWorkspace(ctx context.Context, params *grafana.DeleteWorkspaceInput, optFns ...func(*grafana.Options)) (*grafana.DeleteWorkspaceOutput, error) 14 | ListWorkspaces(ctx context.Context, params *grafana.ListWorkspacesInput, optFns ...func(*grafana.Options)) (*grafana.ListWorkspacesOutput, error) 15 | } 16 | 17 | type Grafana struct { 18 | BaseAwsResource 19 | Client GrafanaAPI 20 | Region string 21 | WorkSpaces []string 22 | } 23 | 24 | func (g *Grafana) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.ManagedPrometheus 26 | } 27 | 28 | func (g *Grafana) Init(cfg aws.Config) { 29 | g.Client = grafana.NewFromConfig(cfg) 30 | } 31 | 32 | func (g *Grafana) ResourceName() string { return "grafana" } 33 | 34 | func (g *Grafana) ResourceIdentifiers() []string { return g.WorkSpaces } 35 | 36 | func (g *Grafana) MaxBatchSize() int { 37 | return 100 38 | } 39 | 40 | func (g *Grafana) Nuke(identifiers []string) error { 41 | if err := g.nukeAll(aws.StringSlice(identifiers)); err != nil { 42 | return errors.WithStackTrace(err) 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (g *Grafana) GetAndSetIdentifiers(ctx context.Context, cnfObj config.Config) ([]string, error) { 49 | identifiers, err := g.getAll(ctx, cnfObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | g.WorkSpaces = aws.ToStringSlice(identifiers) 55 | return g.WorkSpaces, nil 56 | } 57 | -------------------------------------------------------------------------------- /aws/resources/guardduty_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/guardduty" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | ) 10 | 11 | type GuardDutyAPI interface { 12 | GetDetector(ctx context.Context, params *guardduty.GetDetectorInput, optFns ...func(*guardduty.Options)) (*guardduty.GetDetectorOutput, error) 13 | DeleteDetector(ctx context.Context, params *guardduty.DeleteDetectorInput, optFns ...func(*guardduty.Options)) (*guardduty.DeleteDetectorOutput, error) 14 | ListDetectors(ctx context.Context, params *guardduty.ListDetectorsInput, optFns ...func(*guardduty.Options)) (*guardduty.ListDetectorsOutput, error) 15 | } 16 | 17 | type GuardDuty struct { 18 | BaseAwsResource 19 | Client GuardDutyAPI 20 | Region string 21 | detectorIds []string 22 | } 23 | 24 | func (gd *GuardDuty) Init(cfg aws.Config) { 25 | gd.Client = guardduty.NewFromConfig(cfg) 26 | } 27 | 28 | func (gd *GuardDuty) ResourceName() string { 29 | return "guardduty" 30 | } 31 | 32 | func (gd *GuardDuty) ResourceIdentifiers() []string { 33 | return gd.detectorIds 34 | } 35 | 36 | func (gd *GuardDuty) MaxBatchSize() int { 37 | return 10 38 | } 39 | 40 | func (gd *GuardDuty) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 41 | return configObj.GuardDuty 42 | } 43 | 44 | func (gd *GuardDuty) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := gd.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | gd.detectorIds = aws.ToStringSlice(identifiers) 51 | return gd.detectorIds, nil 52 | } 53 | 54 | func (gd *GuardDuty) Nuke(detectorIds []string) error { 55 | return gd.nukeAll(detectorIds) 56 | } 57 | -------------------------------------------------------------------------------- /aws/resources/iam_service_linked_role_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/iam" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type IAMServiceLinkedRolesAPI interface { 13 | ListRoles(ctx context.Context, params *iam.ListRolesInput, optFns ...func(*iam.Options)) (*iam.ListRolesOutput, error) 14 | DeleteServiceLinkedRole(ctx context.Context, params *iam.DeleteServiceLinkedRoleInput, optFns ...func(*iam.Options)) (*iam.DeleteServiceLinkedRoleOutput, error) 15 | GetServiceLinkedRoleDeletionStatus(ctx context.Context, params *iam.GetServiceLinkedRoleDeletionStatusInput, optFns ...func(*iam.Options)) (*iam.GetServiceLinkedRoleDeletionStatusOutput, error) 16 | } 17 | 18 | // IAMServiceLinkedRoles - represents all IAMServiceLinkedRoles on the AWS Account 19 | type IAMServiceLinkedRoles struct { 20 | BaseAwsResource 21 | Client IAMServiceLinkedRolesAPI 22 | RoleNames []string 23 | } 24 | 25 | func (islr *IAMServiceLinkedRoles) Init(cfg aws.Config) { 26 | islr.Client = iam.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (islr *IAMServiceLinkedRoles) ResourceName() string { 31 | return "iam-service-linked-role" 32 | } 33 | 34 | // ResourceIdentifiers - The IAM UserNames 35 | func (islr *IAMServiceLinkedRoles) ResourceIdentifiers() []string { 36 | return islr.RoleNames 37 | } 38 | 39 | // MaxBatchSize Tentative batch size to ensure AWS doesn't throttle 40 | func (islr *IAMServiceLinkedRoles) MaxBatchSize() int { 41 | return 49 42 | } 43 | 44 | func (islr *IAMServiceLinkedRoles) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.IAMServiceLinkedRoles 46 | } 47 | 48 | func (islr *IAMServiceLinkedRoles) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := islr.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | islr.RoleNames = aws.ToStringSlice(identifiers) 55 | return islr.RoleNames, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (islr *IAMServiceLinkedRoles) Nuke(identifiers []string) error { 60 | if err := islr.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/kinesis_firehose.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/firehose" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | func (kf *KinesisFirehose) getAll(_ context.Context, configObj config.Config) ([]*string, error) { 15 | var allStreams []*string 16 | output, err := kf.Client.ListDeliveryStreams(kf.Context, &firehose.ListDeliveryStreamsInput{}) 17 | if err != nil { 18 | return nil, errors.WithStackTrace(err) 19 | } 20 | 21 | for _, stream := range output.DeliveryStreamNames { 22 | if configObj.KinesisFirehose.ShouldInclude(config.ResourceValue{ 23 | Name: aws.String(stream), 24 | }) { 25 | allStreams = append(allStreams, aws.String(stream)) 26 | } 27 | } 28 | 29 | return allStreams, nil 30 | } 31 | 32 | func (kf *KinesisFirehose) nukeAll(identifiers []*string) error { 33 | if len(identifiers) == 0 { 34 | logging.Debugf("No Kinesis Firhose to nuke in region %s", kf.Region) 35 | return nil 36 | } 37 | 38 | logging.Debugf("Deleting all Kinesis Firhose in region %s", kf.Region) 39 | var deleted []*string 40 | for _, id := range identifiers { 41 | _, err := kf.Client.DeleteDeliveryStream(kf.Context, &firehose.DeleteDeliveryStreamInput{ 42 | AllowForceDelete: aws.Bool(true), 43 | DeliveryStreamName: id, 44 | }) 45 | e := report.Entry{ 46 | Identifier: aws.ToString(id), 47 | ResourceType: "Kinesis Firehose", 48 | Error: err, 49 | } 50 | report.Record(e) 51 | 52 | if err != nil { 53 | logging.Debugf("[Failed] %s", err) 54 | } else { 55 | deleted = append(deleted, id) 56 | logging.Debugf("Deleted Kinesis Firehose: %s", *id) 57 | } 58 | } 59 | 60 | logging.Debugf("[OK] %d Kinesis Firehose(s) deleted in %s", len(deleted), kf.Region) 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /aws/resources/kinesis_firehose_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/firehose" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type KinesisFirehoseAPI interface { 13 | DeleteDeliveryStream(ctx context.Context, params *firehose.DeleteDeliveryStreamInput, optFns ...func(*firehose.Options)) (*firehose.DeleteDeliveryStreamOutput, error) 14 | ListDeliveryStreams(ctx context.Context, params *firehose.ListDeliveryStreamsInput, optFns ...func(*firehose.Options)) (*firehose.ListDeliveryStreamsOutput, error) 15 | } 16 | 17 | type KinesisFirehose struct { 18 | BaseAwsResource 19 | Client KinesisFirehoseAPI 20 | Region string 21 | Names []string 22 | } 23 | 24 | func (kf *KinesisFirehose) Init(cfg aws.Config) { 25 | kf.Client = firehose.NewFromConfig(cfg) 26 | } 27 | 28 | // ResourceName - The simple name of the AWS resource 29 | func (kf *KinesisFirehose) ResourceName() string { 30 | return "kinesis-firehose" 31 | } 32 | 33 | // ResourceIdentifiers - The names of the Kinesis Streams 34 | func (kf *KinesisFirehose) ResourceIdentifiers() []string { 35 | return kf.Names 36 | } 37 | 38 | func (kf *KinesisFirehose) MaxBatchSize() int { 39 | // Tentative batch size to ensure AWS doesn't throttle. Note that Kinesis Streams does not support bulk delete, so 40 | // we will be deleting this many in parallel using go routines. We pick 35 here, which is half of what the AWS web 41 | // console will do. We pick a conservative number here to avoid hitting AWS API rate limits. 42 | return 35 43 | } 44 | 45 | func (kf *KinesisFirehose) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 46 | return configObj.KinesisFirehose 47 | } 48 | 49 | func (kf *KinesisFirehose) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 50 | identifiers, err := kf.getAll(c, configObj) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | kf.Names = aws.ToStringSlice(identifiers) 56 | return kf.Names, nil 57 | } 58 | 59 | // Nuke - nuke 'em all!!! 60 | func (kf *KinesisFirehose) Nuke(identifiers []string) error { 61 | if err := kf.nukeAll(aws.StringSlice(identifiers)); err != nil { 62 | return errors.WithStackTrace(err) 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /aws/resources/kinesis_stream_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "regexp" 6 | "testing" 7 | 8 | "github.com/aws/aws-sdk-go-v2/aws" 9 | "github.com/aws/aws-sdk-go-v2/service/kinesis" 10 | "github.com/gruntwork-io/cloud-nuke/config" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | type mockedKinesisClient struct { 15 | KinesisStreamsAPI 16 | ListStreamsOutput kinesis.ListStreamsOutput 17 | DeleteStreamOutput kinesis.DeleteStreamOutput 18 | } 19 | 20 | func (m mockedKinesisClient) ListStreams(ctx context.Context, params *kinesis.ListStreamsInput, optFns ...func(*kinesis.Options)) (*kinesis.ListStreamsOutput, error) { 21 | return &m.ListStreamsOutput, nil 22 | } 23 | 24 | func (m mockedKinesisClient) DeleteStream(ctx context.Context, params *kinesis.DeleteStreamInput, optFns ...func(*kinesis.Options)) (*kinesis.DeleteStreamOutput, error) { 25 | return &m.DeleteStreamOutput, nil 26 | } 27 | 28 | func TestKinesisStreams_GetAll(t *testing.T) { 29 | t.Parallel() 30 | 31 | testName1 := "stream1" 32 | testName2 := "stream2" 33 | ks := KinesisStreams{ 34 | Client: mockedKinesisClient{ 35 | ListStreamsOutput: kinesis.ListStreamsOutput{ 36 | StreamNames: []string{testName1, testName2}, 37 | }, 38 | }, 39 | } 40 | 41 | tests := map[string]struct { 42 | configObj config.ResourceType 43 | expected []string 44 | }{ 45 | "emptyFilter": { 46 | configObj: config.ResourceType{}, 47 | expected: []string{testName1, testName2}, 48 | }, 49 | "nameExclusionFilter": { 50 | configObj: config.ResourceType{ 51 | ExcludeRule: config.FilterRule{ 52 | NamesRegExp: []config.Expression{{ 53 | RE: *regexp.MustCompile(testName1), 54 | }}}, 55 | }, 56 | expected: []string{testName2}, 57 | }, 58 | } 59 | for name, tc := range tests { 60 | t.Run(name, func(t *testing.T) { 61 | names, err := ks.getAll(context.Background(), config.Config{ 62 | KinesisStream: tc.configObj, 63 | }) 64 | require.NoError(t, err) 65 | require.Equal(t, tc.expected, aws.ToStringSlice(names)) 66 | }) 67 | } 68 | 69 | } 70 | 71 | func TestKinesisStreams_NukeAll(t *testing.T) { 72 | t.Parallel() 73 | 74 | ks := KinesisStreams{ 75 | Client: mockedKinesisClient{ 76 | DeleteStreamOutput: kinesis.DeleteStreamOutput{}, 77 | }, 78 | } 79 | 80 | err := ks.nukeAll([]*string{aws.String("test")}) 81 | require.NoError(t, err) 82 | } 83 | -------------------------------------------------------------------------------- /aws/resources/kinesis_stream_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/kinesis" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type KinesisStreamsAPI interface { 13 | ListStreams(ctx context.Context, params *kinesis.ListStreamsInput, optFns ...func(*kinesis.Options)) (*kinesis.ListStreamsOutput, error) 14 | DeleteStream(ctx context.Context, params *kinesis.DeleteStreamInput, optFns ...func(*kinesis.Options)) (*kinesis.DeleteStreamOutput, error) 15 | } 16 | 17 | // KinesisStreams - represents all Kinesis streams 18 | type KinesisStreams struct { 19 | BaseAwsResource 20 | Client KinesisStreamsAPI 21 | Region string 22 | Names []string 23 | } 24 | 25 | func (ks *KinesisStreams) Init(cfg aws.Config) { 26 | ks.Client = kinesis.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - The simple name of the AWS resource 30 | func (ks *KinesisStreams) ResourceName() string { 31 | return "kinesis-stream" 32 | } 33 | 34 | // ResourceIdentifiers - The names of the Kinesis Streams 35 | func (ks *KinesisStreams) ResourceIdentifiers() []string { 36 | return ks.Names 37 | } 38 | 39 | func (ks *KinesisStreams) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle. Note that Kinesis Streams does not support bulk delete, so 41 | // we will be deleting this many in parallel using go routines. We pick 35 here, which is half of what the AWS web 42 | // console will do. We pick a conservative number here to avoid hitting AWS API rate limits. 43 | return 35 44 | } 45 | 46 | func (ks *KinesisStreams) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 47 | return configObj.KinesisStream 48 | } 49 | 50 | func (ks *KinesisStreams) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 51 | identifiers, err := ks.getAll(c, configObj) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | ks.Names = aws.ToStringSlice(identifiers) 57 | return ks.Names, nil 58 | } 59 | 60 | // Nuke - nuke 'em all!!! 61 | func (ks *KinesisStreams) Nuke(identifiers []string) error { 62 | if err := ks.nukeAll(aws.StringSlice(identifiers)); err != nil { 63 | return errors.WithStackTrace(err) 64 | } 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /aws/resources/lambda_layer_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/lambda" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type LambdaLayersAPI interface { 13 | DeleteLayerVersion(ctx context.Context, params *lambda.DeleteLayerVersionInput, optFns ...func(*lambda.Options)) (*lambda.DeleteLayerVersionOutput, error) 14 | ListLayers(ctx context.Context, params *lambda.ListLayersInput, optFns ...func(*lambda.Options)) (*lambda.ListLayersOutput, error) 15 | ListLayerVersions(ctx context.Context, params *lambda.ListLayerVersionsInput, optFns ...func(*lambda.Options)) (*lambda.ListLayerVersionsOutput, error) 16 | } 17 | 18 | type LambdaLayers struct { 19 | BaseAwsResource 20 | Client LambdaLayersAPI 21 | Region string 22 | LambdaFunctionNames []string 23 | } 24 | 25 | func (ll *LambdaLayers) Init(cfg aws.Config) { 26 | ll.Client = lambda.NewFromConfig(cfg) 27 | } 28 | 29 | func (ll *LambdaLayers) ResourceName() string { 30 | return "lambda_layer" 31 | } 32 | 33 | // ResourceIdentifiers - The names of the lambda functions 34 | func (ll *LambdaLayers) ResourceIdentifiers() []string { 35 | return ll.LambdaFunctionNames 36 | } 37 | 38 | func (ll *LambdaLayers) MaxBatchSize() int { 39 | // Tentative batch size to ensure AWS doesn't throttle 40 | return 49 41 | } 42 | 43 | func (ll *LambdaLayers) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 44 | return configObj.LambdaLayer 45 | } 46 | 47 | func (ll *LambdaLayers) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 48 | identifiers, err := ll.getAll(c, configObj) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | ll.LambdaFunctionNames = aws.ToStringSlice(identifiers) 54 | return ll.LambdaFunctionNames, nil 55 | } 56 | 57 | // Nuke - nuke 'em all!!! 58 | func (ll *LambdaLayers) Nuke(identifiers []string) error { 59 | if err := ll.nukeAll(aws.StringSlice(identifiers)); err != nil { 60 | return errors.WithStackTrace(err) 61 | } 62 | 63 | return nil 64 | } 65 | 66 | type LambdaVersionDeleteError struct { 67 | name string 68 | } 69 | 70 | func (e LambdaVersionDeleteError) Error() string { 71 | return "Lambda Function:" + e.name + "was not deleted" 72 | } 73 | -------------------------------------------------------------------------------- /aws/resources/lambda_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/lambda" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type LambdaFunctionsAPI interface { 13 | DeleteFunction(ctx context.Context, params *lambda.DeleteFunctionInput, optFns ...func(*lambda.Options)) (*lambda.DeleteFunctionOutput, error) 14 | ListFunctions(ctx context.Context, params *lambda.ListFunctionsInput, optFns ...func(*lambda.Options)) (*lambda.ListFunctionsOutput, error) 15 | } 16 | 17 | type LambdaFunctions struct { 18 | BaseAwsResource 19 | Client LambdaFunctionsAPI 20 | Region string 21 | LambdaFunctionNames []string 22 | } 23 | 24 | func (lf *LambdaFunctions) Init(cfg aws.Config) { 25 | lf.Client = lambda.NewFromConfig(cfg) 26 | } 27 | 28 | func (lf *LambdaFunctions) ResourceName() string { 29 | return "lambda" 30 | } 31 | 32 | // ResourceIdentifiers - The names of the lambda functions 33 | func (lf *LambdaFunctions) ResourceIdentifiers() []string { 34 | return lf.LambdaFunctionNames 35 | } 36 | 37 | func (lf *LambdaFunctions) MaxBatchSize() int { 38 | // Tentative batch size to ensure AWS doesn't throttle 39 | return 49 40 | } 41 | 42 | func (lf *LambdaFunctions) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 43 | return configObj.LambdaFunction 44 | } 45 | 46 | func (lf *LambdaFunctions) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := lf.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | lf.LambdaFunctionNames = aws.ToStringSlice(identifiers) 53 | return lf.LambdaFunctionNames, nil 54 | } 55 | 56 | // Nuke - nuke 'em all!!! 57 | func (lf *LambdaFunctions) Nuke(identifiers []string) error { 58 | if err := lf.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | 62 | return nil 63 | } 64 | 65 | type LambdaDeleteError struct { 66 | name string 67 | } 68 | 69 | func (e LambdaDeleteError) Error() string { 70 | return "Lambda Function:" + e.name + "was not deleted" 71 | } 72 | -------------------------------------------------------------------------------- /aws/resources/launch_config.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/autoscaling" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | // Returns a formatted string of Launch config Names 15 | func (lc *LaunchConfigs) getAll(c context.Context, configObj config.Config) ([]*string, error) { 16 | result, err := lc.Client.DescribeLaunchConfigurations(lc.Context, &autoscaling.DescribeLaunchConfigurationsInput{}) 17 | if err != nil { 18 | return nil, errors.WithStackTrace(err) 19 | } 20 | 21 | var configNames []*string 22 | for _, c := range result.LaunchConfigurations { 23 | if configObj.LaunchConfiguration.ShouldInclude(config.ResourceValue{ 24 | Time: c.CreatedTime, 25 | Name: c.LaunchConfigurationName, 26 | }) { 27 | configNames = append(configNames, c.LaunchConfigurationName) 28 | } 29 | } 30 | 31 | return configNames, nil 32 | } 33 | 34 | // Deletes all Launch configurations 35 | func (lc *LaunchConfigs) nukeAll(configNames []*string) error { 36 | 37 | if len(configNames) == 0 { 38 | logging.Debugf("No Launch Configurations to nuke in region %s", lc.Region) 39 | return nil 40 | } 41 | 42 | logging.Debugf("Deleting all Launch Configurations in region %s", lc.Region) 43 | var deletedConfigNames []*string 44 | 45 | for _, configName := range configNames { 46 | params := &autoscaling.DeleteLaunchConfigurationInput{ 47 | LaunchConfigurationName: configName, 48 | } 49 | 50 | _, err := lc.Client.DeleteLaunchConfiguration(lc.Context, params) 51 | 52 | // Record status of this resource 53 | e := report.Entry{ 54 | Identifier: aws.ToString(configName), 55 | ResourceType: "Launch configuration", 56 | Error: err, 57 | } 58 | report.Record(e) 59 | 60 | if err != nil { 61 | logging.Errorf("[Failed] %s", err) 62 | } else { 63 | deletedConfigNames = append(deletedConfigNames, configName) 64 | logging.Debugf("Deleted Launch configuration: %s", *configName) 65 | } 66 | } 67 | 68 | logging.Debugf("[OK] %d Launch Configuration(s) deleted in %s", len(deletedConfigNames), lc.Region) 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /aws/resources/launch_config_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/autoscaling" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type LaunchConfigsAPI interface { 13 | DescribeLaunchConfigurations(ctx context.Context, params *autoscaling.DescribeLaunchConfigurationsInput, optFns ...func(*autoscaling.Options)) (*autoscaling.DescribeLaunchConfigurationsOutput, error) 14 | DeleteLaunchConfiguration(ctx context.Context, params *autoscaling.DeleteLaunchConfigurationInput, optFns ...func(*autoscaling.Options)) (*autoscaling.DeleteLaunchConfigurationOutput, error) 15 | } 16 | 17 | // LaunchConfigs - represents all launch configurations 18 | type LaunchConfigs struct { 19 | BaseAwsResource 20 | Client LaunchConfigsAPI 21 | Region string 22 | LaunchConfigurationNames []string 23 | } 24 | 25 | func (lc *LaunchConfigs) Init(cfg aws.Config) { 26 | lc.Client = autoscaling.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (lc *LaunchConfigs) ResourceName() string { 31 | return "lc" 32 | } 33 | 34 | func (lc *LaunchConfigs) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The names of the launch configurations 40 | func (lc *LaunchConfigs) ResourceIdentifiers() []string { 41 | return lc.LaunchConfigurationNames 42 | } 43 | 44 | func (lc *LaunchConfigs) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.LaunchConfiguration 46 | } 47 | 48 | func (lc *LaunchConfigs) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := lc.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | lc.LaunchConfigurationNames = aws.ToStringSlice(identifiers) 55 | return lc.LaunchConfigurationNames, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (lc *LaunchConfigs) Nuke(identifiers []string) error { 60 | if err := lc.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/launch_template_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type LaunchTemplatesAPI interface { 13 | DescribeLaunchTemplates(ctx context.Context, params *ec2.DescribeLaunchTemplatesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeLaunchTemplatesOutput, error) 14 | DeleteLaunchTemplate(ctx context.Context, params *ec2.DeleteLaunchTemplateInput, optFns ...func(*ec2.Options)) (*ec2.DeleteLaunchTemplateOutput, error) 15 | } 16 | 17 | // LaunchTemplates - represents all launch templates 18 | type LaunchTemplates struct { 19 | BaseAwsResource 20 | Client LaunchTemplatesAPI 21 | Region string 22 | LaunchTemplateNames []string 23 | } 24 | 25 | func (lt *LaunchTemplates) Init(cfg aws.Config) { 26 | lt.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (lt *LaunchTemplates) ResourceName() string { 31 | return "lt" 32 | } 33 | 34 | func (lt *LaunchTemplates) MaxBatchSize() int { 35 | // Tentative batch size to ensure AWS doesn't throttle 36 | return 49 37 | } 38 | 39 | // ResourceIdentifiers - The names of the launch templates 40 | func (lt *LaunchTemplates) ResourceIdentifiers() []string { 41 | return lt.LaunchTemplateNames 42 | } 43 | 44 | func (lt *LaunchTemplates) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.LaunchTemplate 46 | } 47 | 48 | func (lt *LaunchTemplates) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := lt.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | lt.LaunchTemplateNames = aws.ToStringSlice(identifiers) 55 | return lt.LaunchTemplateNames, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (lt *LaunchTemplates) Nuke(identifiers []string) error { 60 | if err := lt.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/managed_prometheus_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/amp" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type ManagedPrometheusAPI interface { 13 | ListWorkspaces(ctx context.Context, input *amp.ListWorkspacesInput, f ...func(*amp.Options)) (*amp.ListWorkspacesOutput, error) 14 | DeleteWorkspace(ctx context.Context, params *amp.DeleteWorkspaceInput, optFns ...func(*amp.Options)) (*amp.DeleteWorkspaceOutput, error) 15 | } 16 | 17 | type ManagedPrometheus struct { 18 | BaseAwsResource 19 | Client ManagedPrometheusAPI 20 | Region string 21 | WorkSpaces []string 22 | } 23 | 24 | func (a *ManagedPrometheus) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 25 | return configObj.ManagedPrometheus 26 | } 27 | 28 | func (a *ManagedPrometheus) Init(cfg aws.Config) { 29 | a.Client = amp.NewFromConfig(cfg) 30 | } 31 | 32 | func (a *ManagedPrometheus) ResourceName() string { return "managed-prometheus" } 33 | 34 | func (a *ManagedPrometheus) ResourceIdentifiers() []string { return a.WorkSpaces } 35 | 36 | func (a *ManagedPrometheus) MaxBatchSize() int { 37 | return 100 38 | } 39 | 40 | func (a *ManagedPrometheus) Nuke(identifiers []string) error { 41 | if err := a.nukeAll(aws.StringSlice(identifiers)); err != nil { 42 | return errors.WithStackTrace(err) 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (a *ManagedPrometheus) GetAndSetIdentifiers(ctx context.Context, cnfObj config.Config) ([]string, error) { 49 | identifiers, err := a.getAll(ctx, cnfObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | a.WorkSpaces = aws.ToStringSlice(identifiers) 55 | return a.WorkSpaces, nil 56 | } 57 | -------------------------------------------------------------------------------- /aws/resources/msk_cluster_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/kafka" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type MSKClusterAPI interface { 13 | ListClustersV2(ctx context.Context, params *kafka.ListClustersV2Input, optFns ...func(*kafka.Options)) (*kafka.ListClustersV2Output, error) 14 | DeleteCluster(ctx context.Context, params *kafka.DeleteClusterInput, optFns ...func(*kafka.Options)) (*kafka.DeleteClusterOutput, error) 15 | } 16 | 17 | // MSKCluster - represents all AWS Managed Streaming for Kafka clusters that should be deleted. 18 | type MSKCluster struct { 19 | BaseAwsResource 20 | Client MSKClusterAPI 21 | Region string 22 | ClusterArns []string 23 | } 24 | 25 | func (m *MSKCluster) Init(cfg aws.Config) { 26 | m.Client = kafka.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (m *MSKCluster) ResourceName() string { 31 | return "msk-cluster" 32 | } 33 | 34 | // ResourceIdentifiers - The instance ids of the AWS Managed Streaming for Kafka clusters 35 | func (m *MSKCluster) ResourceIdentifiers() []string { 36 | return m.ClusterArns 37 | } 38 | 39 | func (m *MSKCluster) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle. Note that nat gateway does not support bulk delete, so 41 | // we will be deleting this many in parallel using go routines. We conservatively pick 10 here, both to limit 42 | // overloading the runtime and to avoid AWS throttling with many API calls. 43 | return 10 44 | } 45 | 46 | func (m *MSKCluster) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 47 | return configObj.MSKCluster 48 | } 49 | 50 | func (m *MSKCluster) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 51 | identifiers, err := m.getAll(c, configObj) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | m.ClusterArns = aws.ToStringSlice(identifiers) 57 | return m.ClusterArns, nil 58 | } 59 | 60 | // Nuke - nuke 'em all!!! 61 | func (m *MSKCluster) Nuke(identifiers []string) error { 62 | if err := m.nukeAll(aws.StringSlice(identifiers)); err != nil { 63 | return errors.WithStackTrace(err) 64 | } 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /aws/resources/nat_gateway_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type NatGatewaysAPI interface { 13 | DeleteNatGateway(ctx context.Context, params *ec2.DeleteNatGatewayInput, optFns ...func(*ec2.Options)) (*ec2.DeleteNatGatewayOutput, error) 14 | DescribeNatGateways(ctx context.Context, params *ec2.DescribeNatGatewaysInput, optFns ...func(*ec2.Options)) (*ec2.DescribeNatGatewaysOutput, error) 15 | } 16 | 17 | // NatGateways - represents all AWS secrets manager secrets that should be deleted. 18 | type NatGateways struct { 19 | BaseAwsResource 20 | Client NatGatewaysAPI 21 | Region string 22 | NatGatewayIDs []string 23 | } 24 | 25 | func (ngw *NatGateways) Init(cfg aws.Config) { 26 | ngw.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (ngw *NatGateways) ResourceName() string { 31 | return "nat-gateway" 32 | } 33 | 34 | // ResourceIdentifiers - The instance ids of the ec2 instances 35 | func (ngw *NatGateways) ResourceIdentifiers() []string { 36 | return ngw.NatGatewayIDs 37 | } 38 | 39 | func (ngw *NatGateways) MaxBatchSize() int { 40 | // Tentative batch size to ensure AWS doesn't throttle. Note that nat gateway does not support bulk delete, so 41 | // we will be deleting this many in parallel using go routines. We conservatively pick 10 here, both to limit 42 | // overloading the runtime and to avoid AWS throttling with many API calls. 43 | return 10 44 | } 45 | 46 | func (ngw *NatGateways) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 47 | return configObj.NatGateway 48 | } 49 | 50 | func (ngw *NatGateways) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 51 | identifiers, err := ngw.getAll(c, configObj) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | ngw.NatGatewayIDs = aws.ToStringSlice(identifiers) 57 | return ngw.NatGatewayIDs, nil 58 | } 59 | 60 | // Nuke - nuke 'em all!!! 61 | func (ngw *NatGateways) Nuke(identifiers []string) error { 62 | if err := ngw.nukeAll(aws.StringSlice(identifiers)); err != nil { 63 | return errors.WithStackTrace(err) 64 | } 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /aws/resources/rds_cluster_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type DBClustersAPI interface { 13 | DeleteDBCluster(ctx context.Context, params *rds.DeleteDBClusterInput, optFns ...func(*rds.Options)) (*rds.DeleteDBClusterOutput, error) 14 | DescribeDBClusters(ctx context.Context, params *rds.DescribeDBClustersInput, optFns ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error) 15 | } 16 | type DBClusters struct { 17 | BaseAwsResource 18 | Client DBClustersAPI 19 | Region string 20 | InstanceNames []string 21 | } 22 | 23 | func (instance *DBClusters) Init(cfg aws.Config) { 24 | instance.Client = rds.NewFromConfig(cfg) 25 | } 26 | 27 | func (instance *DBClusters) ResourceName() string { 28 | return "rds-cluster" 29 | } 30 | 31 | // ResourceIdentifiers - The instance names of the rds db instances 32 | func (instance *DBClusters) ResourceIdentifiers() []string { 33 | return instance.InstanceNames 34 | } 35 | 36 | func (instance *DBClusters) MaxBatchSize() int { 37 | // Tentative batch size to ensure AWS doesn't throttle 38 | return 49 39 | } 40 | 41 | func (instance *DBClusters) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 42 | return configObj.DBClusters 43 | } 44 | 45 | func (instance *DBClusters) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := instance.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | instance.InstanceNames = aws.ToStringSlice(identifiers) 52 | return instance.InstanceNames, nil 53 | } 54 | 55 | // Nuke - nuke 'em all!!! 56 | func (instance *DBClusters) Nuke(identifiers []string) error { 57 | if err := instance.nukeAll(aws.StringSlice(identifiers)); err != nil { 58 | return errors.WithStackTrace(err) 59 | } 60 | 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /aws/resources/rds_global_cluster_membership_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type DBGCMembershipsAPI interface { 13 | DescribeGlobalClusters(ctx context.Context, params *rds.DescribeGlobalClustersInput, optFns ...func(*rds.Options)) (*rds.DescribeGlobalClustersOutput, error) 14 | RemoveFromGlobalCluster(ctx context.Context, params *rds.RemoveFromGlobalClusterInput, optFns ...func(*rds.Options)) (*rds.RemoveFromGlobalClusterOutput, error) 15 | } 16 | 17 | type DBGlobalClusterMemberships struct { 18 | BaseAwsResource 19 | Client DBGCMembershipsAPI 20 | Region string 21 | InstanceNames []string 22 | } 23 | 24 | func (instance *DBGlobalClusterMemberships) Init(cfg aws.Config) { 25 | instance.Client = rds.NewFromConfig(cfg) 26 | } 27 | 28 | func (instance *DBGlobalClusterMemberships) ResourceName() string { 29 | return "rds-global-cluster-membership" 30 | } 31 | 32 | // ResourceIdentifiers - The instance names of the rds db instances 33 | func (instance *DBGlobalClusterMemberships) ResourceIdentifiers() []string { 34 | return instance.InstanceNames 35 | } 36 | 37 | func (instance *DBGlobalClusterMemberships) MaxBatchSize() int { 38 | // Tentative batch size to ensure AWS doesn't throttle 39 | return 49 40 | } 41 | 42 | func (instance *DBGlobalClusterMemberships) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 43 | return configObj.DBGlobalClusterMemberships 44 | } 45 | 46 | func (instance *DBGlobalClusterMemberships) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := instance.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | instance.InstanceNames = aws.ToStringSlice(identifiers) 53 | return instance.InstanceNames, nil 54 | } 55 | 56 | // Nuke - nuke 'em all!!! 57 | func (instance *DBGlobalClusterMemberships) Nuke(identifiers []string) error { 58 | if err := instance.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /aws/resources/rds_global_cluster_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type DBGlobalClustersAPI interface { 13 | DescribeGlobalClusters(ctx context.Context, params *rds.DescribeGlobalClustersInput, optFns ...func(*rds.Options)) (*rds.DescribeGlobalClustersOutput, error) 14 | DeleteGlobalCluster(ctx context.Context, params *rds.DeleteGlobalClusterInput, optFns ...func(*rds.Options)) (*rds.DeleteGlobalClusterOutput, error) 15 | } 16 | 17 | type DBGlobalClusters struct { 18 | BaseAwsResource 19 | Client DBGlobalClustersAPI 20 | Region string 21 | InstanceNames []string 22 | } 23 | 24 | func (instance *DBGlobalClusters) Init(cfg aws.Config) { 25 | instance.Client = rds.NewFromConfig(cfg) 26 | } 27 | 28 | func (instance *DBGlobalClusters) ResourceName() string { 29 | return "rds-global-cluster" 30 | } 31 | 32 | // ResourceIdentifiers - The instance names of the rds db instances 33 | func (instance *DBGlobalClusters) ResourceIdentifiers() []string { 34 | return instance.InstanceNames 35 | } 36 | 37 | func (instance *DBGlobalClusters) MaxBatchSize() int { 38 | // Tentative batch size to ensure AWS doesn't throttle 39 | return 49 40 | } 41 | 42 | func (instance *DBGlobalClusters) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 43 | return configObj.DBGlobalClusters 44 | } 45 | 46 | func (instance *DBGlobalClusters) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := instance.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | instance.InstanceNames = aws.ToStringSlice(identifiers) 53 | return instance.InstanceNames, nil 54 | } 55 | 56 | // Nuke - nuke 'em all!!! 57 | func (instance *DBGlobalClusters) Nuke(identifiers []string) error { 58 | if err := instance.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /aws/resources/rds_parameter_group_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type RdsParameterGroupAPI interface { 13 | DeleteDBParameterGroup(ctx context.Context, params *rds.DeleteDBParameterGroupInput, optFns ...func(*rds.Options)) (*rds.DeleteDBParameterGroupOutput, error) 14 | DescribeDBParameterGroups(ctx context.Context, params *rds.DescribeDBParameterGroupsInput, optFns ...func(*rds.Options)) (*rds.DescribeDBParameterGroupsOutput, error) 15 | } 16 | type RdsParameterGroup struct { 17 | BaseAwsResource 18 | Client RdsParameterGroupAPI 19 | Region string 20 | GroupNames []string 21 | } 22 | 23 | func (pg *RdsParameterGroup) Init(cfg aws.Config) { 24 | pg.Client = rds.NewFromConfig(cfg) 25 | } 26 | 27 | func (pg *RdsParameterGroup) ResourceName() string { 28 | return "rds-parameter-group" 29 | } 30 | 31 | // ResourceIdentifiers - The names of the rds parameter group 32 | func (pg *RdsParameterGroup) ResourceIdentifiers() []string { 33 | return pg.GroupNames 34 | } 35 | 36 | func (pg *RdsParameterGroup) MaxBatchSize() int { 37 | // Tentative batch size to ensure AWS doesn't throttle 38 | return 49 39 | } 40 | 41 | func (pg *RdsParameterGroup) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 42 | return configObj.RdsParameterGroup 43 | } 44 | 45 | func (pg *RdsParameterGroup) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := pg.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | pg.GroupNames = aws.ToStringSlice(identifiers) 52 | return pg.GroupNames, nil 53 | } 54 | 55 | // Nuke - nuke 'em all!!! 56 | func (pg *RdsParameterGroup) Nuke(identifiers []string) error { 57 | if err := pg.nukeAll(aws.StringSlice(identifiers)); err != nil { 58 | return errors.WithStackTrace(err) 59 | } 60 | 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /aws/resources/rds_proxy.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | func (rdp *RdsProxy) getAll(_ context.Context, configObj config.Config) ([]*string, error) { 15 | var names []*string 16 | paginator := rds.NewDescribeDBProxiesPaginator(rdp.Client, &rds.DescribeDBProxiesInput{}) 17 | 18 | for paginator.HasMorePages() { 19 | page, err := paginator.NextPage(rdp.Context) 20 | if err != nil { 21 | return nil, errors.WithStackTrace(err) 22 | } 23 | 24 | for _, proxy := range page.DBProxies { 25 | if configObj.RdsProxy.ShouldInclude(config.ResourceValue{ 26 | Name: proxy.DBProxyName, 27 | Time: proxy.CreatedDate, 28 | }) { 29 | names = append(names, proxy.DBProxyName) 30 | } 31 | } 32 | } 33 | 34 | return names, nil 35 | } 36 | func (rdp *RdsProxy) nukeAll(identifiers []*string) error { 37 | if len(identifiers) == 0 { 38 | logging.Debugf("No RDS proxy in region %s", rdp.Region) 39 | return nil 40 | } 41 | 42 | logging.Debugf("Deleting all DB Proxies in region %s", rdp.Region) 43 | var deleted []*string 44 | 45 | for _, identifier := range identifiers { 46 | logging.Debugf("[RDS Proxy] Deleting %s in region %s", *identifier, rdp.Region) 47 | 48 | _, err := rdp.Client.DeleteDBProxy( 49 | rdp.Context, 50 | &rds.DeleteDBProxyInput{ 51 | DBProxyName: identifier, 52 | }) 53 | if err != nil { 54 | logging.Errorf("[RDS Proxy] Error deleting RDS Proxy %s: %s", *identifier, err) 55 | } else { 56 | deleted = append(deleted, identifier) 57 | logging.Debugf("[RDS Proxy] Deleted RDS Proxy %s", *identifier) 58 | } 59 | 60 | // Record status of this resource 61 | e := report.Entry{ 62 | Identifier: aws.ToString(identifier), 63 | ResourceType: rdp.ResourceName(), 64 | Error: err, 65 | } 66 | report.Record(e) 67 | } 68 | 69 | logging.Debugf("[OK] %d RDS DB proxi(s) nuked in %s", len(deleted), rdp.Region) 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /aws/resources/rds_proxy_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type RdsProxyAPI interface { 13 | DescribeDBProxies(ctx context.Context, params *rds.DescribeDBProxiesInput, optFns ...func(*rds.Options)) (*rds.DescribeDBProxiesOutput, error) 14 | DeleteDBProxy(ctx context.Context, params *rds.DeleteDBProxyInput, optFns ...func(*rds.Options)) (*rds.DeleteDBProxyOutput, error) 15 | } 16 | type RdsProxy struct { 17 | BaseAwsResource 18 | Client RdsProxyAPI 19 | Region string 20 | GroupNames []string 21 | } 22 | 23 | func (pg *RdsProxy) Init(cfg aws.Config) { 24 | pg.Client = rds.NewFromConfig(cfg) 25 | } 26 | 27 | func (pg *RdsProxy) ResourceName() string { 28 | return "rds-proxy" 29 | } 30 | 31 | // ResourceIdentifiers - The names of the rds parameter group 32 | func (pg *RdsProxy) ResourceIdentifiers() []string { 33 | return pg.GroupNames 34 | } 35 | 36 | func (pg *RdsProxy) MaxBatchSize() int { 37 | // Tentative batch size to ensure AWS doesn't throttle 38 | return 49 39 | } 40 | 41 | func (pg *RdsProxy) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 42 | return configObj.RdsProxy 43 | } 44 | 45 | func (pg *RdsProxy) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := pg.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | pg.GroupNames = aws.ToStringSlice(identifiers) 52 | return pg.GroupNames, nil 53 | } 54 | 55 | // Nuke - nuke 'em all!!! 56 | func (pg *RdsProxy) Nuke(identifiers []string) error { 57 | if err := pg.nukeAll(aws.StringSlice(identifiers)); err != nil { 58 | return errors.WithStackTrace(err) 59 | } 60 | 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /aws/resources/rds_snapshot.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/cloud-nuke/util" 12 | ) 13 | 14 | func (snapshot *RdsSnapshot) getAll(c context.Context, configObj config.Config) ([]*string, error) { 15 | var identifiers []*string 16 | 17 | // Initialize the paginator 18 | paginator := rds.NewDescribeDBSnapshotsPaginator(snapshot.Client, &rds.DescribeDBSnapshotsInput{}) 19 | 20 | // Iterate through the pages 21 | for paginator.HasMorePages() { 22 | page, err := paginator.NextPage(c) 23 | if err != nil { 24 | logging.Debugf("[RDS Snapshot] Failed to list snapshots: %s", err) 25 | return nil, err 26 | } 27 | 28 | // Process each snapshot in the current page 29 | for _, s := range page.DBSnapshots { 30 | if configObj.RdsSnapshot.ShouldInclude(config.ResourceValue{ 31 | Name: s.DBSnapshotIdentifier, 32 | Time: s.SnapshotCreateTime, 33 | Tags: util.ConvertRDSTypeTagsToMap(s.TagList), 34 | }) { 35 | identifiers = append(identifiers, s.DBSnapshotIdentifier) 36 | } 37 | } 38 | } 39 | 40 | return identifiers, nil 41 | } 42 | 43 | func (snapshot *RdsSnapshot) nukeAll(identifiers []*string) error { 44 | for _, identifier := range identifiers { 45 | logging.Debugf("[RDS Snapshot] Deleting %s in region %s", *identifier, snapshot.Region) 46 | _, err := snapshot.Client.DeleteDBSnapshot(snapshot.Context, &rds.DeleteDBSnapshotInput{ 47 | DBSnapshotIdentifier: identifier, 48 | }) 49 | if err != nil { 50 | logging.Errorf("[RDS Snapshot] Error deleting RDS Snapshot %s: %s", *identifier, err) 51 | } else { 52 | logging.Debugf("[RDS Snapshot] Deleted RDS Snapshot %s", *identifier) 53 | } 54 | 55 | // Record status of this resource 56 | e := report.Entry{ 57 | Identifier: aws.ToString(identifier), 58 | ResourceType: snapshot.ResourceName(), 59 | Error: err, 60 | } 61 | report.Record(e) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/rds_snapshot_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type RdsSnapshotAPI interface { 13 | DescribeDBSnapshots(ctx context.Context, params *rds.DescribeDBSnapshotsInput, optFns ...func(*rds.Options)) (*rds.DescribeDBSnapshotsOutput, error) 14 | DeleteDBSnapshot(ctx context.Context, params *rds.DeleteDBSnapshotInput, optFns ...func(*rds.Options)) (*rds.DeleteDBSnapshotOutput, error) 15 | } 16 | 17 | type RdsSnapshot struct { 18 | BaseAwsResource 19 | Client RdsSnapshotAPI 20 | Region string 21 | Identifiers []string 22 | } 23 | 24 | func (snapshot *RdsSnapshot) Init(cfg aws.Config) { 25 | snapshot.Client = rds.NewFromConfig(cfg) 26 | } 27 | 28 | func (snapshot *RdsSnapshot) ResourceName() string { 29 | return "rds-snapshot" 30 | } 31 | 32 | func (snapshot *RdsSnapshot) ResourceIdentifiers() []string { 33 | return snapshot.Identifiers 34 | } 35 | 36 | func (snapshot *RdsSnapshot) MaxBatchSize() int { 37 | return 49 38 | } 39 | 40 | func (snapshot *RdsSnapshot) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 41 | return configObj.RdsSnapshot 42 | } 43 | 44 | func (snapshot *RdsSnapshot) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := snapshot.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | snapshot.Identifiers = aws.ToStringSlice(identifiers) 51 | return snapshot.Identifiers, nil 52 | } 53 | 54 | // Nuke - nuke 'em all!!! 55 | func (snapshot *RdsSnapshot) Nuke(identifiers []string) error { 56 | if err := snapshot.nukeAll(aws.StringSlice(identifiers)); err != nil { 57 | return errors.WithStackTrace(err) 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /aws/resources/rds_subnet_group_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type DBSubnetGroupsAPI interface { 13 | DescribeDBSubnetGroups(ctx context.Context, params *rds.DescribeDBSubnetGroupsInput, optFns ...func(*rds.Options)) (*rds.DescribeDBSubnetGroupsOutput, error) 14 | DeleteDBSubnetGroup(ctx context.Context, params *rds.DeleteDBSubnetGroupInput, optFns ...func(*rds.Options)) (*rds.DeleteDBSubnetGroupOutput, error) 15 | ListTagsForResource(ctx context.Context, params *rds.ListTagsForResourceInput, optFns ...func(*rds.Options)) (*rds.ListTagsForResourceOutput, error) 16 | } 17 | 18 | type DBSubnetGroups struct { 19 | BaseAwsResource 20 | Client DBSubnetGroupsAPI 21 | Region string 22 | InstanceNames []string 23 | } 24 | 25 | func (dsg *DBSubnetGroups) Init(cfg aws.Config) { 26 | dsg.Client = rds.NewFromConfig(cfg) 27 | } 28 | 29 | func (dsg *DBSubnetGroups) ResourceName() string { 30 | return "rds-subnet-group" 31 | } 32 | 33 | // ResourceIdentifiers - The instance names of the rds db instances 34 | func (dsg *DBSubnetGroups) ResourceIdentifiers() []string { 35 | return dsg.InstanceNames 36 | } 37 | 38 | func (dsg *DBSubnetGroups) MaxBatchSize() int { 39 | // Tentative batch size to ensure AWS doesn't throttle 40 | return 49 41 | } 42 | 43 | func (dsg *DBSubnetGroups) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 44 | return configObj.DBSubnetGroups 45 | } 46 | 47 | func (dsg *DBSubnetGroups) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 48 | identifiers, err := dsg.getAll(c, configObj) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | dsg.InstanceNames = aws.ToStringSlice(identifiers) 54 | return dsg.InstanceNames, nil 55 | } 56 | 57 | // Nuke - nuke 'em all!!! 58 | func (dsg *DBSubnetGroups) Nuke(identifiers []string) error { 59 | if err := dsg.nukeAll(aws.StringSlice(identifiers)); err != nil { 60 | return errors.WithStackTrace(err) 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /aws/resources/rds_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/rds" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type RDSAPI interface { 13 | ModifyDBInstance(ctx context.Context, params *rds.ModifyDBInstanceInput, optFns ...func(*rds.Options)) (*rds.ModifyDBInstanceOutput, error) 14 | DeleteDBInstance(ctx context.Context, params *rds.DeleteDBInstanceInput, optFns ...func(*rds.Options)) (*rds.DeleteDBInstanceOutput, error) 15 | DescribeDBInstances(ctx context.Context, params *rds.DescribeDBInstancesInput, optFns ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) 16 | } 17 | type DBInstances struct { 18 | BaseAwsResource 19 | Client RDSAPI 20 | Region string 21 | InstanceNames []string 22 | } 23 | 24 | func (di *DBInstances) Init(cfg aws.Config) { 25 | di.Client = rds.NewFromConfig(cfg) 26 | } 27 | 28 | func (di *DBInstances) ResourceName() string { 29 | return "rds" 30 | } 31 | 32 | // ResourceIdentifiers - The instance names of the rds db instances 33 | func (di *DBInstances) ResourceIdentifiers() []string { 34 | return di.InstanceNames 35 | } 36 | 37 | func (di *DBInstances) MaxBatchSize() int { 38 | // Tentative batch size to ensure AWS doesn't throttle 39 | return 49 40 | } 41 | 42 | func (di *DBInstances) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 43 | return configObj.DBInstances.ResourceType 44 | } 45 | 46 | func (di *DBInstances) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := di.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | di.InstanceNames = aws.ToStringSlice(identifiers) 53 | return di.InstanceNames, nil 54 | } 55 | 56 | // Nuke - nuke 'em all!!! 57 | func (di *DBInstances) Nuke(identifiers []string) error { 58 | if err := di.nukeAll(aws.StringSlice(identifiers)); err != nil { 59 | return errors.WithStackTrace(err) 60 | } 61 | 62 | return nil 63 | } 64 | 65 | type RdsDeleteError struct { 66 | name string 67 | } 68 | 69 | func (e RdsDeleteError) Error() string { 70 | return "RDS DB Instance:" + e.name + "was not deleted" 71 | } 72 | -------------------------------------------------------------------------------- /aws/resources/redshift_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/redshift" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type RedshiftClustersAPI interface { 13 | DescribeClusters(ctx context.Context, params *redshift.DescribeClustersInput, optFns ...func(*redshift.Options)) (*redshift.DescribeClustersOutput, error) 14 | DeleteCluster(ctx context.Context, params *redshift.DeleteClusterInput, optFns ...func(*redshift.Options)) (*redshift.DeleteClusterOutput, error) 15 | } 16 | type RedshiftClusters struct { 17 | BaseAwsResource 18 | Client RedshiftClustersAPI 19 | Region string 20 | ClusterIdentifiers []string 21 | } 22 | 23 | func (rc *RedshiftClusters) Init(cfg aws.Config) { 24 | rc.Client = redshift.NewFromConfig(cfg) 25 | } 26 | 27 | func (rc *RedshiftClusters) ResourceName() string { 28 | return "redshift" 29 | } 30 | 31 | // ResourceIdentifiers - The instance names of the rds db instances 32 | func (rc *RedshiftClusters) ResourceIdentifiers() []string { 33 | return rc.ClusterIdentifiers 34 | } 35 | 36 | func (rc *RedshiftClusters) MaxBatchSize() int { 37 | // Tentative batch size to ensure AWS doesn't throttle 38 | return 49 39 | } 40 | 41 | func (rc *RedshiftClusters) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 42 | return configObj.Redshift 43 | } 44 | 45 | func (rc *RedshiftClusters) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := rc.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | rc.ClusterIdentifiers = aws.ToStringSlice(identifiers) 52 | return rc.ClusterIdentifiers, nil 53 | } 54 | 55 | // Nuke - nuke 'em all!!! 56 | func (rc *RedshiftClusters) Nuke(identifiers []string) error { 57 | if err := rc.nukeAll(aws.StringSlice(identifiers)); err != nil { 58 | return errors.WithStackTrace(err) 59 | } 60 | 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /aws/resources/route53_traffic_policy.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/route53" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | ) 12 | 13 | func (r *Route53TrafficPolicy) getAll(_ context.Context, configObj config.Config) ([]*string, error) { 14 | var ids []*string 15 | 16 | result, err := r.Client.ListTrafficPolicies(r.Context, &route53.ListTrafficPoliciesInput{}) 17 | if err != nil { 18 | logging.Errorf("[Failed] unable to list traffic policies: %v", err) 19 | return nil, err 20 | } 21 | 22 | for _, summary := range result.TrafficPolicySummaries { 23 | if configObj.Route53TrafficPolicy.ShouldInclude(config.ResourceValue{ 24 | Name: summary.Name, 25 | }) { 26 | ids = append(ids, summary.Id) 27 | // store the corresponding version, as this is required for nuking 28 | r.versionMap[*summary.Id] = summary.LatestVersion 29 | } 30 | } 31 | 32 | return ids, nil 33 | } 34 | 35 | func (r *Route53TrafficPolicy) nukeAll(identifiers []*string) (err error) { 36 | if len(identifiers) == 0 { 37 | logging.Debugf("No Route53 Traffic Policy to nuke in region %s", r.Region) 38 | return nil 39 | } 40 | logging.Debugf("Deleting all Route53 Traffic Policy in region %s", r.Region) 41 | 42 | var deletedIds []*string 43 | for _, id := range identifiers { 44 | _, err := r.Client.DeleteTrafficPolicy(r.Context, &route53.DeleteTrafficPolicyInput{ 45 | Id: id, 46 | Version: r.versionMap[*id], 47 | }) 48 | 49 | // Record status of this resource 50 | e := report.Entry{ 51 | Identifier: aws.ToString(id), 52 | ResourceType: "Route53 Traffic Policy", 53 | Error: err, 54 | } 55 | report.Record(e) 56 | 57 | if err != nil { 58 | logging.Errorf("[Failed] %s: %s", *id, err) 59 | } else { 60 | deletedIds = append(deletedIds, id) 61 | logging.Debugf("Deleted Route53 Traffic Policy: %s", aws.ToString(id)) 62 | } 63 | } 64 | 65 | logging.Debugf("[OK] %d Route53 Traffic Policy(s) deleted in %s", len(deletedIds), r.Region) 66 | 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /aws/resources/route53_traffic_policy_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/route53" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type Route53TrafficPolicyAPI interface { 13 | ListTrafficPolicies(ctx context.Context, params *route53.ListTrafficPoliciesInput, optFns ...func(*route53.Options)) (*route53.ListTrafficPoliciesOutput, error) 14 | DeleteTrafficPolicy(ctx context.Context, params *route53.DeleteTrafficPolicyInput, optFns ...func(*route53.Options)) (*route53.DeleteTrafficPolicyOutput, error) 15 | } 16 | 17 | // Route53TrafficPolicy - represents all Route53TrafficPolicy 18 | type Route53TrafficPolicy struct { 19 | BaseAwsResource 20 | Client Route53TrafficPolicyAPI 21 | Region string 22 | Ids []string 23 | versionMap map[string]*int32 24 | } 25 | 26 | func (r *Route53TrafficPolicy) Init(cfg aws.Config) { 27 | r.Client = route53.NewFromConfig(cfg) 28 | r.versionMap = make(map[string]*int32) 29 | } 30 | 31 | // ResourceName - the simple name of the aws resource 32 | func (r *Route53TrafficPolicy) ResourceName() string { 33 | return "route53-traffic-policy" 34 | } 35 | 36 | func (r *Route53TrafficPolicy) MaxBatchSize() int { 37 | // Tentative batch size to ensure AWS doesn't throttle 38 | return 49 39 | } 40 | 41 | // ResourceIdentifiers - The ids of traffic policies 42 | func (r *Route53TrafficPolicy) ResourceIdentifiers() []string { 43 | return r.Ids 44 | } 45 | func (r *Route53TrafficPolicy) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 46 | return configObj.Route53TrafficPolicy 47 | } 48 | 49 | func (r *Route53TrafficPolicy) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 50 | identifiers, err := r.getAll(c, configObj) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | r.Ids = aws.ToStringSlice(identifiers) 56 | return r.Ids, nil 57 | } 58 | 59 | // Nuke - nuke 'em all!!! 60 | func (r *Route53TrafficPolicy) Nuke(identifiers []string) error { 61 | if err := r.nukeAll(aws.StringSlice(identifiers)); err != nil { 62 | return errors.WithStackTrace(err) 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /aws/resources/s3_access_point_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/s3control" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type S3ControlAccessPointAPI interface { 13 | ListAccessPoints(ctx context.Context, params *s3control.ListAccessPointsInput, optFns ...func(*s3control.Options)) (*s3control.ListAccessPointsOutput, error) 14 | DeleteAccessPoint(ctx context.Context, params *s3control.DeleteAccessPointInput, optFns ...func(*s3control.Options)) (*s3control.DeleteAccessPointOutput, error) 15 | } 16 | type S3AccessPoint struct { 17 | BaseAwsResource 18 | Client S3ControlAccessPointAPI 19 | Region string 20 | AccessPoints []string 21 | AccountID *string 22 | } 23 | 24 | func (ap *S3AccessPoint) Init(cfg aws.Config) { 25 | ap.Client = s3control.NewFromConfig(cfg) 26 | } 27 | 28 | func (ap *S3AccessPoint) ResourceName() string { 29 | return "s3-ap" 30 | } 31 | 32 | func (ap *S3AccessPoint) ResourceIdentifiers() []string { 33 | return ap.AccessPoints 34 | } 35 | 36 | func (ap *S3AccessPoint) MaxBatchSize() int { 37 | return 5 38 | } 39 | 40 | func (ap *S3AccessPoint) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 41 | return configObj.S3AccessPoint 42 | } 43 | 44 | func (ap *S3AccessPoint) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := ap.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | ap.AccessPoints = aws.ToStringSlice(identifiers) 51 | return ap.AccessPoints, nil 52 | } 53 | 54 | func (ap *S3AccessPoint) Nuke(identifiers []string) error { 55 | if err := ap.nukeAll(aws.StringSlice(identifiers)); err != nil { 56 | return errors.WithStackTrace(err) 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /aws/resources/s3_multi_region_access_point_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/s3control" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type S3ControlMultiRegionAPI interface { 13 | ListMultiRegionAccessPoints(ctx context.Context, params *s3control.ListMultiRegionAccessPointsInput, optFns ...func(*s3control.Options)) (*s3control.ListMultiRegionAccessPointsOutput, error) 14 | DeleteMultiRegionAccessPoint(ctx context.Context, params *s3control.DeleteMultiRegionAccessPointInput, optFns ...func(*s3control.Options)) (*s3control.DeleteMultiRegionAccessPointOutput, error) 15 | } 16 | type S3MultiRegionAccessPoint struct { 17 | BaseAwsResource 18 | Client S3ControlMultiRegionAPI 19 | Region string 20 | AccessPoints []string 21 | AccountID *string 22 | } 23 | 24 | func (ap *S3MultiRegionAccessPoint) Init(cfg aws.Config) { 25 | ap.Client = s3control.NewFromConfig(cfg) 26 | } 27 | 28 | func (ap *S3MultiRegionAccessPoint) ResourceName() string { 29 | return "s3-mrap" 30 | } 31 | 32 | func (ap *S3MultiRegionAccessPoint) ResourceIdentifiers() []string { 33 | return ap.AccessPoints 34 | } 35 | 36 | func (ap *S3MultiRegionAccessPoint) MaxBatchSize() int { 37 | return 5 38 | } 39 | 40 | func (ap *S3MultiRegionAccessPoint) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 41 | return configObj.S3MultiRegionAccessPoint 42 | } 43 | 44 | func (ap *S3MultiRegionAccessPoint) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := ap.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | ap.AccessPoints = aws.ToStringSlice(identifiers) 51 | return ap.AccessPoints, nil 52 | } 53 | 54 | func (ap *S3MultiRegionAccessPoint) Nuke(identifiers []string) error { 55 | if err := ap.nukeAll(aws.StringSlice(identifiers)); err != nil { 56 | return errors.WithStackTrace(err) 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /aws/resources/s3_object_lambda_access_point_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/s3control" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type S3ControlAPI interface { 13 | ListAccessPointsForObjectLambda(context.Context, *s3control.ListAccessPointsForObjectLambdaInput, ...func(*s3control.Options)) (*s3control.ListAccessPointsForObjectLambdaOutput, error) 14 | DeleteAccessPointForObjectLambda(context.Context, *s3control.DeleteAccessPointForObjectLambdaInput, ...func(*s3control.Options)) (*s3control.DeleteAccessPointForObjectLambdaOutput, error) 15 | } 16 | type S3ObjectLambdaAccessPoint struct { 17 | BaseAwsResource 18 | Client S3ControlAPI 19 | Region string 20 | AccessPoints []string 21 | AccountID *string 22 | } 23 | 24 | func (ap *S3ObjectLambdaAccessPoint) Init(cfg aws.Config) { 25 | ap.Client = s3control.NewFromConfig(cfg) 26 | } 27 | 28 | func (ap *S3ObjectLambdaAccessPoint) ResourceName() string { 29 | return "s3-olap" 30 | } 31 | 32 | func (ap *S3ObjectLambdaAccessPoint) ResourceIdentifiers() []string { 33 | return ap.AccessPoints 34 | } 35 | 36 | func (ap *S3ObjectLambdaAccessPoint) MaxBatchSize() int { 37 | return 5 38 | } 39 | 40 | func (ap *S3ObjectLambdaAccessPoint) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 41 | return configObj.S3ObjectLambdaAccessPoint 42 | } 43 | 44 | func (ap *S3ObjectLambdaAccessPoint) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := ap.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | ap.AccessPoints = aws.ToStringSlice(identifiers) 51 | return ap.AccessPoints, nil 52 | } 53 | 54 | func (ap *S3ObjectLambdaAccessPoint) Nuke(identifiers []string) error { 55 | if err := ap.nukeAll(aws.StringSlice(identifiers)); err != nil { 56 | return errors.WithStackTrace(err) 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /aws/resources/ses_configuration_set.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ses" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | // Returns a formatted string of ses-configuration set names 15 | func (s *SesConfigurationSet) getAll(c context.Context, configObj config.Config) ([]*string, error) { 16 | // Remove default route table, that will be deleted along with its TransitGateway 17 | param := &ses.ListConfigurationSetsInput{} 18 | 19 | result, err := s.Client.ListConfigurationSets(s.Context, param) 20 | if err != nil { 21 | return nil, errors.WithStackTrace(err) 22 | } 23 | 24 | var setnames []*string 25 | for _, set := range result.ConfigurationSets { 26 | if configObj.SESConfigurationSet.ShouldInclude(config.ResourceValue{Name: set.Name}) { 27 | setnames = append(setnames, set.Name) 28 | } 29 | } 30 | 31 | return setnames, nil 32 | } 33 | 34 | // Deletes all sets 35 | func (s *SesConfigurationSet) nukeAll(sets []*string) error { 36 | if len(sets) == 0 { 37 | logging.Debugf("No SES configuration sets to nuke in region %s", s.Region) 38 | return nil 39 | } 40 | 41 | logging.Debugf("Deleting all SES configuration sets in region %s", s.Region) 42 | var deletedSets []*string 43 | 44 | for _, set := range sets { 45 | _, err := s.Client.DeleteConfigurationSet(s.Context, &ses.DeleteConfigurationSetInput{ 46 | ConfigurationSetName: set, 47 | }) 48 | 49 | // Record status of this resource 50 | e := report.Entry{ 51 | Identifier: aws.ToString(set), 52 | ResourceType: "SES configuration set", 53 | Error: err, 54 | } 55 | report.Record(e) 56 | 57 | if err != nil { 58 | logging.Debugf("[Failed] %s", err) 59 | } else { 60 | deletedSets = append(deletedSets, set) 61 | logging.Debugf("Deleted SES configuration set: %s", *set) 62 | } 63 | } 64 | 65 | logging.Debugf("[OK] %d SES configuration set(s) deleted in %s", len(deletedSets), s.Region) 66 | 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /aws/resources/ses_configuration_set_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ses" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type SESConfigurationSet interface { 13 | ListConfigurationSets(ctx context.Context, params *ses.ListConfigurationSetsInput, optFns ...func(*ses.Options)) (*ses.ListConfigurationSetsOutput, error) 14 | DeleteConfigurationSet(ctx context.Context, params *ses.DeleteConfigurationSetInput, optFns ...func(*ses.Options)) (*ses.DeleteConfigurationSetOutput, error) 15 | } 16 | 17 | // SesConfigurationSet - represents all SES configuartion set 18 | type SesConfigurationSet struct { 19 | BaseAwsResource 20 | Client SESConfigurationSet 21 | Region string 22 | Ids []string 23 | } 24 | 25 | func (scs *SesConfigurationSet) Init(cfg aws.Config) { 26 | scs.Client = ses.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (scs *SesConfigurationSet) ResourceName() string { 31 | return "ses-configuration-set" 32 | } 33 | 34 | // MaxBatchSize - Tentative batch size to ensure AWS doesn't throttle 35 | func (scs *SesConfigurationSet) MaxBatchSize() int { 36 | return maxBatchSize 37 | } 38 | 39 | // ResourceIdentifiers - The Ids of the configuration set 40 | func (scs *SesConfigurationSet) ResourceIdentifiers() []string { 41 | return scs.Ids 42 | } 43 | 44 | func (scs *SesConfigurationSet) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.SESConfigurationSet 46 | } 47 | 48 | func (scs *SesConfigurationSet) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := scs.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | scs.Ids = aws.ToStringSlice(identifiers) 55 | return scs.Ids, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (scs *SesConfigurationSet) Nuke(identifiers []string) error { 60 | if err := scs.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/ses_email_templates.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ses" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | // Returns a formatted string of email template names 15 | func (sem *SesEmailTemplates) getAll(c context.Context, configObj config.Config) ([]*string, error) { 16 | param := &ses.ListTemplatesInput{} 17 | 18 | result, err := sem.Client.ListTemplates(sem.Context, param) 19 | if err != nil { 20 | return nil, errors.WithStackTrace(err) 21 | } 22 | 23 | var templates []*string 24 | for _, template := range result.TemplatesMetadata { 25 | createdAt := template.CreatedTimestamp 26 | if configObj.SESEmailTemplates.ShouldInclude(config.ResourceValue{ 27 | Name: template.Name, 28 | Time: createdAt, 29 | }) { 30 | templates = append(templates, template.Name) 31 | } 32 | } 33 | 34 | return templates, nil 35 | } 36 | 37 | // Deletes all templates 38 | func (sem *SesEmailTemplates) nukeAll(templates []*string) error { 39 | if len(templates) == 0 { 40 | logging.Debugf("No SES email templates to nuke in region %s", sem.Region) 41 | return nil 42 | } 43 | 44 | logging.Debugf("Deleting all SES email templates in region %s", sem.Region) 45 | var deletedIds []*string 46 | 47 | for _, template := range templates { 48 | params := &ses.DeleteTemplateInput{ 49 | TemplateName: template, 50 | } 51 | 52 | _, err := sem.Client.DeleteTemplate(sem.Context, params) 53 | 54 | // Record status of this resource 55 | e := report.Entry{ 56 | Identifier: aws.ToString(template), 57 | ResourceType: "SES email templates", 58 | Error: err, 59 | } 60 | report.Record(e) 61 | 62 | if err != nil { 63 | logging.Debugf("[Failed] %s", err) 64 | } else { 65 | deletedIds = append(deletedIds, template) 66 | logging.Debugf("Deleted SES email templates: %s", *template) 67 | } 68 | } 69 | 70 | logging.Debugf("[OK] %d SES email template(s) deleted in %s", len(deletedIds), sem.Region) 71 | 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /aws/resources/ses_email_templates_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ses" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type SESAPI interface { 13 | ListTemplates(ctx context.Context, params *ses.ListTemplatesInput, optFns ...func(*ses.Options)) (*ses.ListTemplatesOutput, error) 14 | DeleteTemplate(ctx context.Context, params *ses.DeleteTemplateInput, optFns ...func(*ses.Options)) (*ses.DeleteTemplateOutput, error) 15 | } 16 | 17 | // SesEmailTemplates - represents all ses email templates 18 | type SesEmailTemplates struct { 19 | BaseAwsResource 20 | Client SESAPI 21 | Region string 22 | Ids []string 23 | } 24 | 25 | func (s *SesEmailTemplates) Init(cfg aws.Config) { 26 | s.Client = ses.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (set *SesEmailTemplates) ResourceName() string { 31 | return "ses-email-template" 32 | } 33 | 34 | // MaxBatchSize - Tentative batch size to ensure AWS doesn't throttle 35 | func (set *SesEmailTemplates) MaxBatchSize() int { 36 | return maxBatchSize 37 | } 38 | 39 | // ResourceIdentifiers - The names of the ses email templates 40 | func (set *SesEmailTemplates) ResourceIdentifiers() []string { 41 | return set.Ids 42 | } 43 | 44 | func (set *SesEmailTemplates) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 45 | return configObj.SESEmailTemplates 46 | } 47 | 48 | func (set *SesEmailTemplates) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 49 | identifiers, err := set.getAll(c, configObj) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | set.Ids = aws.ToStringSlice(identifiers) 55 | return set.Ids, nil 56 | } 57 | 58 | // Nuke - nuke 'em all!!! 59 | func (set *SesEmailTemplates) Nuke(identifiers []string) error { 60 | if err := set.nukeAll(aws.StringSlice(identifiers)); err != nil { 61 | return errors.WithStackTrace(err) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /aws/resources/ses_identity.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ses" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | // Returns a formatted string of ses-identities IDs 15 | func (sid *SesIdentities) getAll(c context.Context, configObj config.Config) ([]*string, error) { 16 | 17 | param := &ses.ListIdentitiesInput{} 18 | 19 | result, err := sid.Client.ListIdentities(sid.Context, param) 20 | if err != nil { 21 | return nil, errors.WithStackTrace(err) 22 | } 23 | 24 | var ids []*string 25 | for _, id := range result.Identities { 26 | if configObj.SESIdentity.ShouldInclude(config.ResourceValue{Name: aws.String(id)}) { 27 | ids = append(ids, aws.String(id)) 28 | } 29 | } 30 | 31 | return ids, nil 32 | } 33 | 34 | // Deletes all identities 35 | func (sid *SesIdentities) nukeAll(ids []*string) error { 36 | if len(ids) == 0 { 37 | logging.Debugf("No SES identities to nuke in region %s", sid.Region) 38 | return nil 39 | } 40 | 41 | logging.Debugf("Deleting all SES identities in region %s", sid.Region) 42 | var deletedIds []*string 43 | 44 | for _, id := range ids { 45 | params := &ses.DeleteIdentityInput{ 46 | Identity: id, 47 | } 48 | _, err := sid.Client.DeleteIdentity(sid.Context, params) 49 | // Record status of this resource 50 | e := report.Entry{ 51 | Identifier: aws.ToString(id), 52 | ResourceType: "SES identity", 53 | Error: err, 54 | } 55 | report.Record(e) 56 | 57 | if err != nil { 58 | logging.Debugf("[Failed] %s", err) 59 | } else { 60 | deletedIds = append(deletedIds, id) 61 | logging.Debugf("Deleted SES identity: %s", *id) 62 | } 63 | } 64 | 65 | logging.Debugf("[OK] %d SES identity(s) deleted in %s", len(deletedIds), sid.Region) 66 | 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /aws/resources/ses_identity_test.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | "regexp" 6 | "testing" 7 | 8 | "github.com/aws/aws-sdk-go-v2/aws" 9 | "github.com/aws/aws-sdk-go-v2/service/ses" 10 | "github.com/gruntwork-io/cloud-nuke/config" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | type mockedSesIdentities struct { 15 | SESIdentityAPI 16 | DeleteIdentityOutput ses.DeleteIdentityOutput 17 | ListIdentitiesOutput ses.ListIdentitiesOutput 18 | } 19 | 20 | func (m mockedSesIdentities) ListIdentities(_ context.Context, _ *ses.ListIdentitiesInput, _ ...func(*ses.Options)) (*ses.ListIdentitiesOutput, error) { 21 | return &m.ListIdentitiesOutput, nil 22 | } 23 | 24 | func (m mockedSesIdentities) DeleteIdentity(_ context.Context, _ *ses.DeleteIdentityInput, _ ...func(*ses.Options)) (*ses.DeleteIdentityOutput, error) { 25 | return &m.DeleteIdentityOutput, nil 26 | } 27 | 28 | func TestSesIdentities_GetAll(t *testing.T) { 29 | t.Parallel() 30 | 31 | id1 := "test-id-1" 32 | id2 := "test-id-2" 33 | identity := SesIdentities{ 34 | Client: mockedSesIdentities{ 35 | ListIdentitiesOutput: ses.ListIdentitiesOutput{ 36 | Identities: []string{ 37 | (id1), 38 | (id2), 39 | }, 40 | }, 41 | }, 42 | } 43 | 44 | tests := map[string]struct { 45 | configObj config.ResourceType 46 | expected []string 47 | }{ 48 | "emptyFilter": { 49 | configObj: config.ResourceType{}, 50 | expected: []string{id1, id2}, 51 | }, 52 | "nameExclusionFilter": { 53 | configObj: config.ResourceType{ 54 | ExcludeRule: config.FilterRule{ 55 | NamesRegExp: []config.Expression{{ 56 | RE: *regexp.MustCompile(id2), 57 | }}}, 58 | }, 59 | expected: []string{id1}, 60 | }, 61 | } 62 | for name, tc := range tests { 63 | t.Run(name, func(t *testing.T) { 64 | names, err := identity.getAll(context.Background(), config.Config{ 65 | SESIdentity: tc.configObj, 66 | }) 67 | require.NoError(t, err) 68 | require.Equal(t, tc.expected, aws.ToStringSlice(names)) 69 | }) 70 | } 71 | } 72 | 73 | func TestSesIdentities_NukeAll(t *testing.T) { 74 | t.Parallel() 75 | 76 | identity := SesIdentities{ 77 | Client: mockedSesIdentities{ 78 | DeleteIdentityOutput: ses.DeleteIdentityOutput{}, 79 | }, 80 | } 81 | 82 | err := identity.nukeAll([]*string{aws.String("test")}) 83 | require.NoError(t, err) 84 | } 85 | -------------------------------------------------------------------------------- /aws/resources/ses_identity_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ses" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type SESIdentityAPI interface { 13 | ListIdentities(ctx context.Context, params *ses.ListIdentitiesInput, optFns ...func(*ses.Options)) (*ses.ListIdentitiesOutput, error) 14 | DeleteIdentity(ctx context.Context, params *ses.DeleteIdentityInput, optFns ...func(*ses.Options)) (*ses.DeleteIdentityOutput, error) 15 | } 16 | 17 | // SesIdentities - represents all SES identities 18 | type SesIdentities struct { 19 | BaseAwsResource 20 | Client SESIdentityAPI 21 | Region string 22 | Ids []string 23 | } 24 | 25 | func (Sid *SesIdentities) Init(cfg aws.Config) { 26 | Sid.Client = ses.NewFromConfig(cfg) 27 | } 28 | 29 | func (Sid *SesIdentities) ResourceName() string { 30 | return "ses-identity" 31 | } 32 | 33 | func (Sid *SesIdentities) MaxBatchSize() int { 34 | return maxBatchSize 35 | } 36 | 37 | func (Sid *SesIdentities) ResourceIdentifiers() []string { 38 | return Sid.Ids 39 | } 40 | 41 | func (Sid *SesIdentities) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 42 | return configObj.SESIdentity 43 | } 44 | 45 | func (Sid *SesIdentities) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := Sid.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | Sid.Ids = aws.ToStringSlice(identifiers) 52 | return Sid.Ids, nil 53 | } 54 | 55 | func (Sid *SesIdentities) Nuke(identifiers []string) error { 56 | if err := Sid.nukeAll(aws.StringSlice(identifiers)); err != nil { 57 | return errors.WithStackTrace(err) 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /aws/resources/snapshot_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | 9 | "github.com/gruntwork-io/cloud-nuke/config" 10 | "github.com/gruntwork-io/go-commons/errors" 11 | ) 12 | 13 | type SnapshotAPI interface { 14 | DeleteSnapshot(ctx context.Context, params *ec2.DeleteSnapshotInput, optFns ...func(*ec2.Options)) (*ec2.DeleteSnapshotOutput, error) 15 | DeregisterImage(ctx context.Context, params *ec2.DeregisterImageInput, optFns ...func(*ec2.Options)) (*ec2.DeregisterImageOutput, error) 16 | DescribeImages(ctx context.Context, params *ec2.DescribeImagesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeImagesOutput, error) 17 | DescribeSnapshots(ctx context.Context, params *ec2.DescribeSnapshotsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeSnapshotsOutput, error) 18 | } 19 | 20 | // Snapshots - represents all user owned Snapshots 21 | type Snapshots struct { 22 | BaseAwsResource 23 | Client SnapshotAPI 24 | Region string 25 | SnapshotIds []string 26 | } 27 | 28 | func (s *Snapshots) Init(cfg aws.Config) { 29 | s.Client = ec2.NewFromConfig(cfg) 30 | } 31 | 32 | // ResourceName - the simple name of the aws resource 33 | func (s *Snapshots) ResourceName() string { 34 | return "snap" 35 | } 36 | 37 | // ResourceIdentifiers - The Snapshot ids 38 | func (s *Snapshots) ResourceIdentifiers() []string { 39 | return s.SnapshotIds 40 | } 41 | 42 | func (s *Snapshots) MaxBatchSize() int { 43 | // Tentative batch size to ensure AWS doesn't throttle 44 | return 49 45 | } 46 | 47 | func (s *Snapshots) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 48 | return configObj.Snapshots 49 | } 50 | 51 | func (s *Snapshots) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 52 | identifiers, err := s.getAll(c, configObj) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | s.SnapshotIds = aws.ToStringSlice(identifiers) 58 | return s.SnapshotIds, nil 59 | } 60 | 61 | // Nuke - nuke 'em all!!! 62 | func (s *Snapshots) Nuke(identifiers []string) error { 63 | if err := s.nukeAll(aws.StringSlice(identifiers)); err != nil { 64 | return errors.WithStackTrace(err) 65 | } 66 | 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /aws/resources/sns_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/sns" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type SNSTopicAPI interface { 13 | DeleteTopic(ctx context.Context, params *sns.DeleteTopicInput, optFns ...func(*sns.Options)) (*sns.DeleteTopicOutput, error) 14 | ListTopics(context.Context, *sns.ListTopicsInput, ...func(*sns.Options)) (*sns.ListTopicsOutput, error) 15 | ListTagsForResource(ctx context.Context, params *sns.ListTagsForResourceInput, optFns ...func(*sns.Options)) (*sns.ListTagsForResourceOutput, error) 16 | TagResource(ctx context.Context, params *sns.TagResourceInput, optFns ...func(*sns.Options)) (*sns.TagResourceOutput, error) 17 | } 18 | 19 | type SNSTopic struct { 20 | BaseAwsResource 21 | Client SNSTopicAPI 22 | Region string 23 | Arns []string 24 | } 25 | 26 | func (s *SNSTopic) Init(cfg aws.Config) { 27 | s.Client = sns.NewFromConfig(cfg) 28 | } 29 | 30 | func (s *SNSTopic) ResourceName() string { 31 | return "snstopic" 32 | } 33 | 34 | func (s *SNSTopic) ResourceIdentifiers() []string { 35 | return s.Arns 36 | } 37 | 38 | func (s *SNSTopic) MaxBatchSize() int { 39 | return 50 40 | } 41 | 42 | func (s *SNSTopic) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 43 | return configObj.SNS 44 | } 45 | 46 | func (s *SNSTopic) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 47 | identifiers, err := s.getAll(c, configObj) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | s.Arns = aws.ToStringSlice(identifiers) 53 | return s.Arns, nil 54 | } 55 | 56 | func (s *SNSTopic) Nuke(identifiers []string) error { 57 | if err := s.nukeAll(aws.StringSlice(identifiers)); err != nil { 58 | return errors.WithStackTrace(err) 59 | } 60 | return nil 61 | } 62 | 63 | // custom errors 64 | 65 | type TooManySNSTopicsErr struct{} 66 | 67 | func (err TooManySNSTopicsErr) Error() string { 68 | return "Too many SNS Topics requested at once." 69 | } 70 | -------------------------------------------------------------------------------- /aws/resources/sqs_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/sqs" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type SqsQueueAPI interface { 13 | DeleteQueue(ctx context.Context, params *sqs.DeleteQueueInput, optFns ...func(*sqs.Options)) (*sqs.DeleteQueueOutput, error) 14 | GetQueueAttributes(ctx context.Context, params *sqs.GetQueueAttributesInput, optFns ...func(*sqs.Options)) (*sqs.GetQueueAttributesOutput, error) 15 | ListQueues(context.Context, *sqs.ListQueuesInput, ...func(*sqs.Options)) (*sqs.ListQueuesOutput, error) 16 | } 17 | 18 | // SqsQueue - represents all sqs queues 19 | type SqsQueue struct { 20 | BaseAwsResource 21 | Client SqsQueueAPI 22 | Region string 23 | QueueUrls []string 24 | } 25 | 26 | func (sq *SqsQueue) Init(cfg aws.Config) { 27 | sq.Client = sqs.NewFromConfig(cfg) 28 | } 29 | 30 | // ResourceName - the simple name of the aws resource 31 | func (sq *SqsQueue) ResourceName() string { 32 | return "sqs" 33 | } 34 | 35 | func (sq *SqsQueue) MaxBatchSize() int { 36 | // Tentative batch size to ensure AWS doesn't throttle 37 | return 49 38 | } 39 | 40 | // ResourceIdentifiers - The arn's of the sqs queues 41 | func (sq *SqsQueue) ResourceIdentifiers() []string { 42 | return sq.QueueUrls 43 | } 44 | 45 | func (sq *SqsQueue) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 46 | return configObj.SQS 47 | } 48 | 49 | func (sq *SqsQueue) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 50 | identifiers, err := sq.getAll(c, configObj) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | sq.QueueUrls = aws.ToStringSlice(identifiers) 56 | return sq.QueueUrls, nil 57 | } 58 | 59 | // Nuke - nuke 'em all!!! 60 | func (sq *SqsQueue) Nuke(identifiers []string) error { 61 | if err := sq.nukeAll(aws.StringSlice(identifiers)); err != nil { 62 | return errors.WithStackTrace(err) 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /aws/resources/tgw_peering_attachment.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/cloud-nuke/logging" 10 | "github.com/gruntwork-io/cloud-nuke/report" 11 | "github.com/gruntwork-io/go-commons/errors" 12 | ) 13 | 14 | func (tgpa *TransitGatewayPeeringAttachment) getAll(c context.Context, configObj config.Config) ([]*string, error) { 15 | var ids []*string 16 | paginator := ec2.NewDescribeTransitGatewayPeeringAttachmentsPaginator(tgpa.Client, &ec2.DescribeTransitGatewayPeeringAttachmentsInput{}) 17 | for paginator.HasMorePages() { 18 | page, err := paginator.NextPage(c) 19 | if err != nil { 20 | return nil, errors.WithStackTrace(err) 21 | } 22 | 23 | for _, attachment := range page.TransitGatewayPeeringAttachments { 24 | if configObj.TransitGatewayPeeringAttachment.ShouldInclude(config.ResourceValue{ 25 | Time: attachment.CreationTime, 26 | }) { 27 | ids = append(ids, attachment.TransitGatewayAttachmentId) 28 | } 29 | } 30 | } 31 | 32 | return ids, nil 33 | } 34 | 35 | func (tgpa *TransitGatewayPeeringAttachment) nukeAll(ids []*string) error { 36 | for _, id := range ids { 37 | _, err := tgpa.Client.DeleteTransitGatewayPeeringAttachment(tgpa.Context, &ec2.DeleteTransitGatewayPeeringAttachmentInput{ 38 | TransitGatewayAttachmentId: id, 39 | }) 40 | // Record status of this resource 41 | report.Record(report.Entry{ 42 | Identifier: aws.ToString(id), 43 | ResourceType: tgpa.ResourceName(), 44 | Error: err, 45 | }) 46 | if err != nil { 47 | logging.Errorf("[Failed] %s", err) 48 | } else { 49 | logging.Debugf("Deleted Transit Gateway Peering Attachment: %s", *id) 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /aws/resources/tgw_peering_attachment_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type TransitGatewayPeeringAttachmentAPI interface { 13 | DescribeTransitGatewayPeeringAttachments(ctx context.Context, params *ec2.DescribeTransitGatewayPeeringAttachmentsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTransitGatewayPeeringAttachmentsOutput, error) 14 | DeleteTransitGatewayPeeringAttachment(ctx context.Context, params *ec2.DeleteTransitGatewayPeeringAttachmentInput, optFns ...func(*ec2.Options)) (*ec2.DeleteTransitGatewayPeeringAttachmentOutput, error) 15 | } 16 | 17 | // TransitGatewayPeeringAttachment - represents all transit gateways peering attachment 18 | type TransitGatewayPeeringAttachment struct { 19 | BaseAwsResource 20 | Client TransitGatewayPeeringAttachmentAPI 21 | Region string 22 | Ids []string 23 | } 24 | 25 | func (tgpa *TransitGatewayPeeringAttachment) Init(cfg aws.Config) { 26 | tgpa.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | func (tgpa *TransitGatewayPeeringAttachment) ResourceName() string { 30 | return "transit-gateway-peering-attachment" 31 | } 32 | 33 | func (tgpa *TransitGatewayPeeringAttachment) MaxBatchSize() int { 34 | return maxBatchSize 35 | } 36 | 37 | func (tgpa *TransitGatewayPeeringAttachment) ResourceIdentifiers() []string { 38 | return tgpa.Ids 39 | } 40 | 41 | func (tgpa *TransitGatewayPeeringAttachment) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 42 | return configObj.TransitGatewayPeeringAttachment 43 | } 44 | 45 | func (tgpa *TransitGatewayPeeringAttachment) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := tgpa.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | tgpa.Ids = aws.ToStringSlice(identifiers) 52 | return tgpa.Ids, nil 53 | } 54 | 55 | func (tgpa *TransitGatewayPeeringAttachment) Nuke(identifiers []string) error { 56 | if err := tgpa.nukeAll(aws.StringSlice(identifiers)); err != nil { 57 | return errors.WithStackTrace(err) 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /aws/resources/tgw_route_tables_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | 9 | "github.com/gruntwork-io/cloud-nuke/config" 10 | "github.com/gruntwork-io/go-commons/errors" 11 | ) 12 | 13 | type TransitGatewaysRouteTablesAPI interface { 14 | DeleteTransitGatewayRouteTable(ctx context.Context, params *ec2.DeleteTransitGatewayRouteTableInput, optFns ...func(*ec2.Options)) (*ec2.DeleteTransitGatewayRouteTableOutput, error) 15 | DescribeTransitGatewayRouteTables(ctx context.Context, params *ec2.DescribeTransitGatewayRouteTablesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTransitGatewayRouteTablesOutput, error) 16 | } 17 | 18 | // TransitGatewaysRouteTables - represents all transit gateways route tables 19 | type TransitGatewaysRouteTables struct { 20 | BaseAwsResource 21 | Client TransitGatewaysRouteTablesAPI 22 | Region string 23 | Ids []string 24 | } 25 | 26 | func (tgw *TransitGatewaysRouteTables) Init(cfg aws.Config) { 27 | tgw.Client = ec2.NewFromConfig(cfg) 28 | } 29 | 30 | // ResourceName - the simple name of the aws resource 31 | func (tgw *TransitGatewaysRouteTables) ResourceName() string { 32 | return "transit-gateway-route-table" 33 | } 34 | 35 | // MaxBatchSize - Tentative batch size to ensure AWS doesn't throttle 36 | func (tgw *TransitGatewaysRouteTables) MaxBatchSize() int { 37 | return maxBatchSize 38 | } 39 | 40 | // ResourceIdentifiers - The arns of the transit gateways route tables 41 | func (tgw *TransitGatewaysRouteTables) ResourceIdentifiers() []string { 42 | return tgw.Ids 43 | } 44 | 45 | func (tgw *TransitGatewaysRouteTables) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 46 | identifiers, err := tgw.getAll(c, configObj) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | tgw.Ids = aws.ToStringSlice(identifiers) 52 | return tgw.Ids, nil 53 | } 54 | 55 | // Nuke - nuke 'em all!!! 56 | func (tgw *TransitGatewaysRouteTables) Nuke(identifiers []string) error { 57 | if err := tgw.nukeAll(aws.StringSlice(identifiers)); err != nil { 58 | return errors.WithStackTrace(err) 59 | } 60 | 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /aws/resources/tgw_vpc_attachment_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/ec2" 8 | "github.com/gruntwork-io/cloud-nuke/config" 9 | "github.com/gruntwork-io/go-commons/errors" 10 | ) 11 | 12 | type TGWVpcAPI interface { 13 | DeleteTransitGatewayVpcAttachment(ctx context.Context, params *ec2.DeleteTransitGatewayVpcAttachmentInput, optFns ...func(*ec2.Options)) (*ec2.DeleteTransitGatewayVpcAttachmentOutput, error) 14 | DescribeTransitGatewayVpcAttachments(ctx context.Context, params *ec2.DescribeTransitGatewayVpcAttachmentsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTransitGatewayVpcAttachmentsOutput, error) 15 | } 16 | 17 | // TransitGatewaysVpcAttachment represents all transit gateway VPC attachments. 18 | type TransitGatewaysVpcAttachment struct { 19 | BaseAwsResource 20 | Client TGWVpcAPI 21 | Region string 22 | Ids []string 23 | } 24 | 25 | func (tgw *TransitGatewaysVpcAttachment) Init(cfg aws.Config) { 26 | tgw.Client = ec2.NewFromConfig(cfg) 27 | } 28 | 29 | // ResourceName - the simple name of the aws resource 30 | func (tgw *TransitGatewaysVpcAttachment) ResourceName() string { 31 | return "transit-gateway-attachment" 32 | } 33 | 34 | // MaxBatchSize - Tentative batch size to ensure AWS doesn't throttle 35 | func (tgw *TransitGatewaysVpcAttachment) MaxBatchSize() int { 36 | return maxBatchSize 37 | } 38 | 39 | // ResourceIdentifiers - The Ids of the transit gateways 40 | func (tgw *TransitGatewaysVpcAttachment) ResourceIdentifiers() []string { 41 | return tgw.Ids 42 | } 43 | 44 | func (tgw *TransitGatewaysVpcAttachment) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 45 | identifiers, err := tgw.getAll(c, configObj) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | tgw.Ids = aws.ToStringSlice(identifiers) 51 | return tgw.Ids, nil 52 | } 53 | 54 | // Nuke - nuke 'em all!!! 55 | func (tgw *TransitGatewaysVpcAttachment) Nuke(identifiers []string) error { 56 | if err := tgw.nukeAll(aws.StringSlice(identifiers)); err != nil { 57 | return errors.WithStackTrace(err) 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /aws/resources/vpc_lattice_target_group_test.go: -------------------------------------------------------------------------------- 1 | package resources_test 2 | -------------------------------------------------------------------------------- /commands/cli_test.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/gruntwork-io/cloud-nuke/aws" 5 | "github.com/gruntwork-io/cloud-nuke/aws/resources" 6 | "testing" 7 | "time" 8 | 9 | "github.com/gruntwork-io/go-commons/errors" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestParseDuration(t *testing.T) { 14 | now := time.Now() 15 | then, err := parseDurationParam("1h") 16 | if err != nil { 17 | assert.Fail(t, errors.WithStackTrace(err).Error()) 18 | } 19 | 20 | if now.Hour() == 0 { 21 | // At midnight, now.Hour returns 0 so we need to handle that specially. 22 | assert.Equal(t, 23, then.Hour()) 23 | // Also, the date changed, so 1 hour ago will be the previous day. 24 | assert.Equal(t, now.Day()-1, then.Day()) 25 | } else { 26 | assert.Equal(t, now.Hour()-1, then.Hour()) 27 | assert.Equal(t, now.Day(), then.Day()) 28 | } 29 | 30 | assert.Equal(t, now.Month(), then.Month()) 31 | assert.Equal(t, now.Year(), then.Year()) 32 | } 33 | 34 | func TestParseDurationInvalidFormat(t *testing.T) { 35 | value, err := parseDurationParam("") 36 | assert.NoError(t, err) 37 | assert.Nil(t, value) 38 | } 39 | 40 | func TestListResourceTypes(t *testing.T) { 41 | allAWSResourceTypes := aws.ListResourceTypes() 42 | assert.Greater(t, len(allAWSResourceTypes), 0) 43 | assert.Contains(t, allAWSResourceTypes, (&resources.EC2Instances{}).ResourceName()) 44 | } 45 | 46 | func TestIsValidResourceType(t *testing.T) { 47 | allAWSResourceTypes := aws.ListResourceTypes() 48 | ec2ResourceName := (*&resources.EC2Instances{}).ResourceName() 49 | assert.Equal(t, aws.IsValidResourceType(ec2ResourceName, allAWSResourceTypes), true) 50 | assert.Equal(t, aws.IsValidResourceType("xyz", allAWSResourceTypes), false) 51 | } 52 | 53 | func TestIsNukeable(t *testing.T) { 54 | ec2ResourceName := (&resources.EC2Instances{}).ResourceName() 55 | amiResourceName := (&resources.AMIs{}).ResourceName() 56 | 57 | assert.Equal(t, aws.IsNukeable(ec2ResourceName, []string{ec2ResourceName}), true) 58 | assert.Equal(t, aws.IsNukeable(ec2ResourceName, []string{"all"}), true) 59 | assert.Equal(t, aws.IsNukeable(ec2ResourceName, []string{}), true) 60 | assert.Equal(t, aws.IsNukeable(ec2ResourceName, []string{amiResourceName}), false) 61 | } 62 | -------------------------------------------------------------------------------- /commands/errors.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type InvalidFlagError struct { 8 | Name string 9 | Value string 10 | } 11 | 12 | func (e InvalidFlagError) Error() string { 13 | return fmt.Sprintf("Invalid value %s for flag %s", e.Value, e.Name) 14 | } 15 | -------------------------------------------------------------------------------- /config/examples/simple.yaml: -------------------------------------------------------------------------------- 1 | # exclude s3 bucket that match `bucket-.*` but include anything else that match `bucket.*` 2 | s3: 3 | include: 4 | names_regex: 5 | - bucket.* 6 | exclude: 7 | names_regex: 8 | - bucket-.* 9 | -------------------------------------------------------------------------------- /config/mocks/empty.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gruntwork-io/cloud-nuke/ff4b0cb8f03875b3973e692c25c5eb9f4414d58b/config/mocks/empty.yaml -------------------------------------------------------------------------------- /config/mocks/garbage.yaml: -------------------------------------------------------------------------------- 1 | asdlkfjsf: 2 | asdl: 3 | - garbaaaage 4 | - nonsense 5 | - drivel 6 | asdl: 7 | mfeies: 8 | -------------------------------------------------------------------------------- /config/mocks/malformed.yaml: -------------------------------------------------------------------------------- 1 | s3: 2 | include: 3 | - .* 4 | s3: 5 | include: 6 | tags: 7 | - .* 8 | -------------------------------------------------------------------------------- /externalcreds/creds.go: -------------------------------------------------------------------------------- 1 | package externalcreds 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/config" 8 | ) 9 | 10 | func Get(region string) (aws.Config, error) { 11 | cfg, err := config.LoadDefaultConfig(context.TODO(), 12 | config.WithRegion(region), 13 | ) 14 | 15 | if err != nil { 16 | return aws.Config{}, err 17 | } 18 | 19 | return cfg, nil 20 | } 21 | -------------------------------------------------------------------------------- /gcp/resource.go: -------------------------------------------------------------------------------- 1 | package gcp 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/gruntwork-io/cloud-nuke/config" 7 | ) 8 | 9 | // GcpResource is an interface that represents a single GCP resource 10 | type GcpResource interface { 11 | Init(projectID string) 12 | ResourceName() string 13 | ResourceIdentifiers() []string 14 | MaxBatchSize() int 15 | Nuke(identifiers []string) error 16 | GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) 17 | IsNukable(string) (bool, error) 18 | GetAndSetResourceConfig(config.Config) config.ResourceType 19 | PrepareContext(context.Context, config.ResourceType) error 20 | } 21 | 22 | // GcpResources is a struct to hold multiple instances of GcpResource. 23 | type GcpResources struct { 24 | Resources []*GcpResource 25 | } 26 | 27 | // GcpProjectResources is a struct that represents the resources found in a single GCP project 28 | type GcpProjectResources struct { 29 | Resources map[string]GcpResources 30 | } 31 | 32 | func (g *GcpProjectResources) GetRegion(region string) GcpResources { 33 | if val, ok := g.Resources[region]; ok { 34 | return val 35 | } 36 | return GcpResources{} 37 | } 38 | 39 | // TotalResourceCount returns the number of resources found, that are eligible for nuking 40 | func (g *GcpProjectResources) TotalResourceCount() int { 41 | total := 0 42 | for _, regionResource := range g.Resources { 43 | for _, resource := range regionResource.Resources { 44 | total += len((*resource).ResourceIdentifiers()) 45 | } 46 | } 47 | return total 48 | } 49 | 50 | // MapResourceTypeToIdentifiers converts a slice of Resources to a map of resource types to their found identifiers 51 | func (g *GcpProjectResources) MapResourceTypeToIdentifiers() map[string][]string { 52 | identifiers := map[string][]string{} 53 | for _, regionResource := range g.Resources { 54 | for _, resource := range regionResource.Resources { 55 | resourceType := (*resource).ResourceName() 56 | if _, ok := identifiers[resourceType]; !ok { 57 | identifiers[resourceType] = []string{} 58 | } 59 | identifiers[resourceType] = append(identifiers[resourceType], (*resource).ResourceIdentifiers()...) 60 | } 61 | } 62 | return identifiers 63 | } 64 | -------------------------------------------------------------------------------- /gcp/resources/gcs_bucket_types.go: -------------------------------------------------------------------------------- 1 | package resources 2 | 3 | import ( 4 | "context" 5 | 6 | "cloud.google.com/go/storage" 7 | "github.com/gruntwork-io/cloud-nuke/config" 8 | ) 9 | 10 | // GCSBucketAPI represents the interface for GCS bucket operations 11 | type GCSBucketAPI interface { 12 | Buckets(ctx context.Context, projectID string) *storage.BucketIterator 13 | Bucket(name string) *storage.BucketHandle 14 | } 15 | 16 | // GCSBuckets represents all GCS buckets in a project 17 | type GCSBuckets struct { 18 | BaseGcpResource 19 | Client GCSBucketAPI 20 | Names []string 21 | } 22 | 23 | func (b *GCSBuckets) Init(projectID string) { 24 | b.BaseGcpResource.Init(projectID) 25 | client, err := storage.NewClient(context.Background()) 26 | if err != nil { 27 | // Handle error appropriately 28 | return 29 | } 30 | b.Client = client 31 | } 32 | 33 | func (b *GCSBuckets) ResourceName() string { 34 | return "gcs-bucket" 35 | } 36 | 37 | func (b *GCSBuckets) ResourceIdentifiers() []string { 38 | return b.Names 39 | } 40 | 41 | func (b *GCSBuckets) MaxBatchSize() int { 42 | // GCS has a relatively high API quota, but we'll be conservative 43 | return 50 44 | } 45 | 46 | func (b *GCSBuckets) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { 47 | // TODO: Add GCS configuration to config package 48 | return config.ResourceType{ 49 | Timeout: "10m", // Default timeout 50 | } 51 | } 52 | 53 | func (b *GCSBuckets) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { 54 | identifiers, err := b.getAll(c, configObj) 55 | if err != nil { 56 | return nil, err 57 | } 58 | 59 | b.Names = identifiers 60 | return b.Names, nil 61 | } 62 | -------------------------------------------------------------------------------- /logging/logger.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pterm/pterm" 6 | "github.com/sirupsen/logrus" 7 | "os" 8 | ) 9 | 10 | var Logger = InitLogger() 11 | 12 | func InitLogger() *logrus.Logger { 13 | logger := logrus.New() 14 | 15 | // Set the desired log level (e.g., Debug, Info, Warn, Error, etc.) 16 | logger.SetLevel(logrus.InfoLevel) 17 | 18 | // You can also set the log output (e.g., os.Stdout, a file, etc.) 19 | logger.SetOutput(os.Stdout) 20 | return logger 21 | } 22 | 23 | // ParseLogLevel parses the log level from the CLI and sets the log level 24 | func ParseLogLevel(logLevel string) error { 25 | parsedLogLevel, err := logrus.ParseLevel(logLevel) 26 | if err != nil { 27 | return fmt.Errorf("invalid log level - %s - %s", logLevel, err) 28 | } 29 | 30 | Logger.SetLevel(parsedLogLevel) 31 | if parsedLogLevel == logrus.DebugLevel { 32 | pterm.EnableDebugMessages() 33 | Logger.Debugf("Setting log level to %s", parsedLogLevel.String()) 34 | } 35 | 36 | return nil 37 | } 38 | 39 | func Debug(msg string) { 40 | pterm.Debug.Println(msg) 41 | } 42 | 43 | func Debugf(msg string, args ...interface{}) { 44 | Debug(fmt.Sprintf(msg, args...)) 45 | } 46 | 47 | func Info(msg string) { 48 | pterm.Info.Println(msg) 49 | } 50 | 51 | func Infof(msg string, args ...interface{}) { 52 | Info(fmt.Sprintf(msg, args...)) 53 | } 54 | 55 | func Error(msg string) { 56 | pterm.Error.Println(msg) 57 | } 58 | 59 | func Errorf(msg string, args ...interface{}) { 60 | Error(fmt.Sprintf(msg, args...)) 61 | } 62 | 63 | func Warn(msg string) { 64 | pterm.Warning.Println(msg) 65 | } 66 | 67 | func Warnf(msg string, args ...interface{}) { 68 | Warn(fmt.Sprintf(msg, args...)) 69 | } 70 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gruntwork-io/cloud-nuke/commands" 5 | "github.com/gruntwork-io/go-commons/entrypoint" 6 | ) 7 | 8 | // VERSION - Set at build time 9 | var VERSION string 10 | 11 | func main() { 12 | app := commands.CreateCli(VERSION) 13 | entrypoint.RunApp(app) 14 | } 15 | -------------------------------------------------------------------------------- /report/report.go: -------------------------------------------------------------------------------- 1 | package report 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/gruntwork-io/cloud-nuke/util" 7 | ) 8 | 9 | /** 10 | Using a global variables to keep track of reports & errors. 11 | 12 | Generally, it is a bad idea to use global variables. However, in this case, it is the easiest way to keep track of 13 | data that are running in parallel. We can explore passing reports/errors from individual resources in the future. 14 | */ 15 | 16 | // Global variables to keep track of errors/progress when nuking resources. 17 | var m = &sync.Mutex{} 18 | var generalErrors = make(map[string]GeneralError) 19 | var records = make(map[string]Entry) 20 | 21 | func GetRecords() map[string]Entry { 22 | return records 23 | } 24 | 25 | func GetErrors() map[string]GeneralError { 26 | return generalErrors 27 | } 28 | 29 | func ResetRecords() { 30 | records = make(map[string]Entry) 31 | } 32 | 33 | func ResetErrors() { 34 | generalErrors = make(map[string]GeneralError) 35 | } 36 | 37 | func Record(e Entry) { 38 | defer m.Unlock() 39 | m.Lock() 40 | 41 | // Transform the aws error into custom error format. 42 | e.Error = util.TransformAWSError(e.Error) 43 | records[e.Identifier] = e 44 | } 45 | 46 | // RecordBatch accepts a BatchEntry that contains a slice of identifiers, loops through them and converts each identifier to 47 | // a standard Entry. This is useful for supporting batch delete workflows in cloud-nuke (such as cloudwatch_dashboards) 48 | func RecordBatch(e BatchEntry) { 49 | for _, identifier := range e.Identifiers { 50 | entry := Entry{ 51 | Identifier: identifier, 52 | ResourceType: e.ResourceType, 53 | Error: e.Error, 54 | } 55 | Record(entry) 56 | } 57 | } 58 | 59 | func RecordError(e GeneralError) { 60 | defer m.Unlock() 61 | m.Lock() 62 | generalErrors[e.Description] = e 63 | } 64 | 65 | type Entry struct { 66 | Identifier string 67 | ResourceType string 68 | Error error 69 | } 70 | 71 | type BatchEntry struct { 72 | Identifiers []string 73 | ResourceType string 74 | Error error 75 | } 76 | 77 | type GeneralError struct { 78 | Error error 79 | ResourceType string 80 | Description string 81 | } 82 | -------------------------------------------------------------------------------- /telemetry/telemetry.go: -------------------------------------------------------------------------------- 1 | package telemetry 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/gruntwork-io/go-commons/telemetry" 7 | ) 8 | 9 | var sendTelemetry = true 10 | var telemetryClient telemetry.MixpanelTelemetryTracker 11 | var cmd = "" 12 | var isCircleCi = false 13 | var account = "" 14 | 15 | func InitTelemetry(name string, version string) { 16 | _, disableTelemetryFlag := os.LookupEnv("DISABLE_TELEMETRY") 17 | isCircleCi = os.Getenv("CIRCLECI") == "true" 18 | sendTelemetry = !disableTelemetryFlag 19 | if sendTelemetry { 20 | telemetryClient = telemetry.NewMixPanelTelemetryClient("https://t.gruntwork.io/", name, version) 21 | } 22 | if len(os.Args) > 1 { 23 | cmd = os.Args[1] 24 | } 25 | } 26 | 27 | func SetAccountId(accountId string) { 28 | account = accountId 29 | } 30 | 31 | func TrackEvent(ctx telemetry.EventContext, extraProperties map[string]interface{}) { 32 | if sendTelemetry { 33 | ctx.Command = cmd 34 | extraProperties["isCircleCi"] = isCircleCi 35 | extraProperties["accountId"] = account 36 | telemetryClient.TrackEvent(ctx, extraProperties) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ui/styles.go: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/charmbracelet/lipgloss" 7 | "github.com/pterm/pterm" 8 | ) 9 | 10 | var ( 11 | FailureEmoji = "❌" 12 | SuccessEmoji = "✅" 13 | FireEmoji = "🔥" 14 | TargetEmoji = "🎯" 15 | ResourceHighlightStyle = lipgloss.NewStyle(). 16 | Bold(true). 17 | Foreground(lipgloss.Color("202")) 18 | BoldWarningTextStyle = lipgloss.NewStyle(). 19 | Padding(1). 20 | Bold(true). 21 | Italic(true). 22 | Foreground(lipgloss.Color("202")) 23 | BlinkingWarningStyle = lipgloss.NewStyle(). 24 | Bold(true). 25 | Italic(true). 26 | Blink(true). 27 | Underline(true). 28 | Foreground(lipgloss.Color("201")) 29 | ) 30 | 31 | // WarningMessage is a convenience method to display the supplied string in our pre-configured BoldWarningTextStyle 32 | func WarningMessage(s string) { 33 | s = strings.ToUpper(s) 34 | s = BoldWarningTextStyle.Render(s) 35 | pterm.Warning.Println(s) 36 | pterm.Println() 37 | } 38 | 39 | // UrgentMessage is a convenience method to display the supplied string in our pre-configured BlinkingWarningStyle 40 | // This is appropriate to use as the final prompt to confirm the user really wants to nuke all selected resources 41 | func UrgentMessage(s string) { 42 | s = strings.ToUpper(s) 43 | s = BlinkingWarningStyle.Render(s) 44 | pterm.Error.Prefix.Text = "CRITICAL" 45 | pterm.Error.Println(s) 46 | // Replace original prefix to avoid weird edge cases 47 | pterm.Error.Prefix.Text = "Error" 48 | pterm.Println() 49 | } 50 | -------------------------------------------------------------------------------- /util/context.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | ) 7 | 8 | const ( 9 | ExcludeFirstSeenTagKey = "exclude-first-seen-tag" 10 | ) 11 | 12 | func GetBoolFromContext(ctx context.Context, key string) (bool, error) { 13 | result, ok := ctx.Value(key).(bool) 14 | if !ok { 15 | return result, errors.New("unable to find the boolean context value or correct type mismatch.") 16 | } 17 | 18 | return result, nil 19 | } 20 | -------------------------------------------------------------------------------- /util/error.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/aws/smithy-go" 9 | ) 10 | 11 | var ErrInSufficientPermission = errors.New("error:INSUFFICIENT_PERMISSION") 12 | var ErrDifferentOwner = errors.New("error:DIFFERENT_OWNER") 13 | var ErrContextExecutionTimeout = errors.New("error:EXECUTION_TIMEOUT") 14 | var ErrInterfaceIDNotFound = errors.New("error:InterfaceIdNotFound") 15 | var ErrInvalidPermisionNotFound = errors.New("error:InvalidPermission.NotFound") 16 | var ErrDeleteProtectionEnabled = errors.New("error:DeleteProtectionEnabled") 17 | var ErrResourceNotFoundException = errors.New("error:ErrResourceNotFoundException") 18 | 19 | const AWsUnauthorizedError string = "UnauthorizedOperation" 20 | const AWSAccessDeniedException string = "AccessDeniedException" 21 | const AwsDryRunSuccess string = "Request would have succeeded, but DryRun flag is set." 22 | 23 | // TransformAWSError 24 | // this function is used to handle AWS errors and mapping them to a custom error message 25 | // This could be part of a larger error-handling strategy that interacts with AWS services, 26 | // providing a more human-readable error message for certain conditions 27 | // ref : https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html 28 | func TransformAWSError(err error) error { 29 | var apiErr smithy.APIError 30 | if errors.As(err, &apiErr) { 31 | switch apiErr.ErrorCode() { 32 | case AWsUnauthorizedError, AWSAccessDeniedException: 33 | return ErrInSufficientPermission 34 | case "RequestCanceled": 35 | return ErrContextExecutionTimeout 36 | case "InvalidNetworkInterfaceID.NotFound": 37 | return ErrInterfaceIDNotFound 38 | case "InvalidPermission.NotFound": 39 | return ErrInvalidPermisionNotFound 40 | case "ResourceNotFoundException": 41 | return ErrResourceNotFoundException 42 | } 43 | 44 | if apiErr.ErrorCode() == "DryRunOperation" && apiErr.ErrorMessage() == AwsDryRunSuccess { 45 | return nil 46 | } 47 | } 48 | 49 | return err 50 | } 51 | 52 | type ResourceExecutionTimeout struct { 53 | Timeout time.Duration 54 | } 55 | 56 | func (err ResourceExecutionTimeout) Error() string { 57 | return fmt.Sprintf("execution timed out after: %v", err.Timeout) 58 | } 59 | -------------------------------------------------------------------------------- /util/get_current_account_id.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/aws/aws-sdk-go-v2/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/sts" 8 | "github.com/gruntwork-io/go-commons/errors" 9 | ) 10 | 11 | const ( 12 | AccountIdKey = "accountId" 13 | ) 14 | 15 | func GetCurrentAccountId(config aws.Config) (string, error) { 16 | stssvc := sts.NewFromConfig(config) 17 | output, err := stssvc.GetCallerIdentity(context.Background(), &sts.GetCallerIdentityInput{}) 18 | if err != nil { 19 | return "", errors.WithStackTrace(err) 20 | } 21 | 22 | return aws.ToString(output.Account), nil 23 | } 24 | -------------------------------------------------------------------------------- /util/string_utils.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "strings" 4 | 5 | func Split(identifiers []string, limit int) [][]string { 6 | if limit < 0 { 7 | limit = -1 * limit 8 | } else if limit == 0 { 9 | return [][]string{identifiers} 10 | } 11 | 12 | var chunk []string 13 | chunks := make([][]string, 0, len(identifiers)/limit+1) 14 | for len(identifiers) >= limit { 15 | chunk, identifiers = identifiers[:limit], identifiers[limit:] 16 | chunks = append(chunks, chunk) 17 | } 18 | if len(identifiers) > 0 { 19 | chunks = append(chunks, identifiers[:]) 20 | } 21 | 22 | return chunks 23 | } 24 | 25 | // Difference returns the elements in `a` that aren't in `b`. 26 | func Difference(a, b []*string) []*string { 27 | mb := make(map[string]bool, len(b)) 28 | for _, x := range b { 29 | mb[*x] = true 30 | } 31 | 32 | var diff []*string 33 | for _, x := range a { 34 | if _, found := mb[*x]; !found { 35 | diff = append(diff, x) 36 | } 37 | } 38 | 39 | return diff 40 | } 41 | 42 | // Truncate accepts a string and a max length. If the max length is less than the string's current length, 43 | // then only the first maxLen characters of the string are returned 44 | func Truncate(s string, maxLen int) string { 45 | if len(s) > maxLen { 46 | return s[:maxLen] 47 | } 48 | return s 49 | } 50 | 51 | // RemoveNewlines will delete all the newlines in a given string, which is useful for making error messages 52 | // "sit" more nicely within their specified table cells in the terminal 53 | func RemoveNewlines(s string) string { 54 | return strings.ReplaceAll(s, "\n", "") 55 | } 56 | -------------------------------------------------------------------------------- /util/time_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | "time" 7 | 8 | "github.com/aws/aws-sdk-go-v2/aws" 9 | ) 10 | 11 | func TestParseTimestamp(t *testing.T) { 12 | type args struct { 13 | timestamp *string 14 | } 15 | tests := []struct { 16 | name string 17 | args args 18 | want *time.Time 19 | wantErr bool 20 | }{ 21 | { 22 | "it should parse legacy firstSeenTag value \"2023-12-19 10:38:44\" correctly", 23 | args{timestamp: aws.String("2023-12-19 10:38:44")}, 24 | newTime(time.Date(2023, 12, 19, 10, 38, 44, 0, time.UTC)), 25 | false, 26 | }, 27 | { 28 | "it should parse RFC3339 firstSeenTag value \"2024-04-12T15:18:05Z\" correctly", 29 | args{timestamp: aws.String("2024-04-12T15:18:05Z")}, 30 | newTime(time.Date(2024, 4, 12, 15, 18, 5, 0, time.UTC)), 31 | false, 32 | }, 33 | } 34 | for _, tt := range tests { 35 | t.Run(tt.name, func(t *testing.T) { 36 | got, err := ParseTimestamp(tt.args.timestamp) 37 | if (err != nil) != tt.wantErr { 38 | t.Errorf("ParseTimestamp() error = %v, wantErr %v", err, tt.wantErr) 39 | return 40 | } 41 | if !reflect.DeepEqual(got, tt.want) { 42 | t.Errorf("ParseTimestamp() = %v, want %v", got, &tt.want) 43 | } 44 | }) 45 | } 46 | } 47 | 48 | func newTime(t time.Time) *time.Time { 49 | return &t 50 | } 51 | -------------------------------------------------------------------------------- /util/unique_id.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | // Returns a unique (ish) id we can attach to resources and tfstate files so they don't conflict with each other 10 | // Uses base 62 to generate a 6 character string that's unlikely to collide with the handful of tests we run in 11 | // parallel. Based on code here: http://stackoverflow.com/a/9543797/483528 12 | func UniqueID() string { 13 | 14 | const BASE_62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 15 | const UNIQUE_ID_LENGTH = 6 // Should be good for 62^6 = 56+ billion combinations 16 | 17 | var out bytes.Buffer 18 | 19 | rand := rand.New(rand.NewSource(time.Now().UnixNano())) 20 | for i := 0; i < UNIQUE_ID_LENGTH; i++ { 21 | out.WriteByte(BASE_62_CHARS[rand.Intn(len(BASE_62_CHARS))]) 22 | } 23 | 24 | return out.String() 25 | } 26 | --------------------------------------------------------------------------------