diff --git a/resources/applicationautoscaling-scalable-targets.go b/resources/applicationautoscaling-scalable-targets.go index 2e762b6e..49627b09 100644 --- a/resources/applicationautoscaling-scalable-targets.go +++ b/resources/applicationautoscaling-scalable-targets.go @@ -2,6 +2,7 @@ package resources import ( "context" + "slices" "github.com/gotidy/ptr" @@ -32,9 +33,16 @@ func (l *ApplicationAutoScalingScalableTargetLister) List(_ context.Context, o i namespaces := applicationautoscaling.ServiceNamespace_Values() + // Note: Workspaces is not a valid namespace for DescribeScalableTargets anymore according to the API + invalidNamespaces := []string{applicationautoscaling.ServiceNamespaceWorkspaces} + params := &applicationautoscaling.DescribeScalableTargetsInput{} resources := make([]resource.Resource, 0) for _, namespace := range namespaces { + if slices.Contains(invalidNamespaces, namespace) { + continue + } + for { params.ServiceNamespace = ptr.String(namespace) resp, err := svc.DescribeScalableTargets(params) diff --git a/resources/cloudfront-distribution-deployments.go b/resources/cloudfront-distribution-deployment.go similarity index 65% rename from resources/cloudfront-distribution-deployments.go rename to resources/cloudfront-distribution-deployment.go index 820bb2ae..c3f4e010 100644 --- a/resources/cloudfront-distribution-deployments.go +++ b/resources/cloudfront-distribution-deployment.go @@ -5,22 +5,17 @@ import ( "fmt" "github.com/gotidy/ptr" + "github.com/sirupsen/logrus" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cloudfront" - "github.com/ekristen/aws-nuke/v3/pkg/nuke" "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" -) + "github.com/ekristen/libnuke/pkg/types" -type CloudFrontDistributionDeployment struct { - svc *cloudfront.CloudFront - distributionID *string - eTag *string - distributionConfig *cloudfront.DistributionConfig - status string -} + "github.com/ekristen/aws-nuke/v3/pkg/nuke" +) const CloudFrontDistributionDeploymentResource = "CloudFrontDistributionDeployment" @@ -61,44 +56,57 @@ func (l *CloudFrontDistributionDeploymentLister) List(_ context.Context, o inter } for _, distribution := range distributions { - params := &cloudfront.GetDistributionInput{ + resp, err := svc.GetDistribution(&cloudfront.GetDistributionInput{ Id: distribution.Id, - } - resp, err := svc.GetDistribution(params) + }) if err != nil { - return nil, err + logrus.WithError(err).Error("unable to get distribution, skipping") + continue } + resources = append(resources, &CloudFrontDistributionDeployment{ svc: svc, - distributionID: resp.Distribution.Id, + ID: resp.Distribution.Id, eTag: resp.ETag, distributionConfig: resp.Distribution.DistributionConfig, - status: ptr.ToString(resp.Distribution.Status), + Status: resp.Distribution.Status, }) } return resources, nil } -func (f *CloudFrontDistributionDeployment) Remove(_ context.Context) error { - f.distributionConfig.Enabled = aws.Bool(false) +type CloudFrontDistributionDeployment struct { + svc *cloudfront.CloudFront + ID *string + Status *string + eTag *string + distributionConfig *cloudfront.DistributionConfig +} + +func (r *CloudFrontDistributionDeployment) Remove(_ context.Context) error { + r.distributionConfig.Enabled = aws.Bool(false) - _, err := f.svc.UpdateDistribution(&cloudfront.UpdateDistributionInput{ - Id: f.distributionID, - DistributionConfig: f.distributionConfig, - IfMatch: f.eTag, + _, err := r.svc.UpdateDistribution(&cloudfront.UpdateDistributionInput{ + Id: r.ID, + DistributionConfig: r.distributionConfig, + IfMatch: r.eTag, }) return err } -func (f *CloudFrontDistributionDeployment) Filter() error { - if !ptr.ToBool(f.distributionConfig.Enabled) && f.status != "InProgress" { +func (r *CloudFrontDistributionDeployment) Filter() error { + if !ptr.ToBool(r.distributionConfig.Enabled) && ptr.ToString(r.Status) != "InProgress" { return fmt.Errorf("already disabled") } return nil } -func (f *CloudFrontDistributionDeployment) String() string { - return *f.distributionID +func (r *CloudFrontDistributionDeployment) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *CloudFrontDistributionDeployment) String() string { + return *r.ID } diff --git a/resources/cloudwatchevents-rules.go b/resources/cloudwatchevents-rule.go similarity index 65% rename from resources/cloudwatchevents-rules.go rename to resources/cloudwatchevents-rule.go index 6813acf5..8ff7fceb 100644 --- a/resources/cloudwatchevents-rules.go +++ b/resources/cloudwatchevents-rule.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "github.com/aws/aws-sdk-go/aws" @@ -10,6 +9,7 @@ import ( "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" ) @@ -47,9 +47,11 @@ func (l *CloudWatchEventsRuleLister) List(_ context.Context, o interface{}) ([]r for _, rule := range resp.Rules { resources = append(resources, &CloudWatchEventsRule{ - svc: svc, - name: rule.Name, - busName: bus.Name, + svc: svc, + Name: rule.Name, + ARN: rule.Arn, + State: rule.State, + EventBusName: bus.Name, }) } } @@ -57,21 +59,27 @@ func (l *CloudWatchEventsRuleLister) List(_ context.Context, o interface{}) ([]r } type CloudWatchEventsRule struct { - svc *cloudwatchevents.CloudWatchEvents - name *string - busName *string + svc *cloudwatchevents.CloudWatchEvents + Name *string + ARN *string + State *string + EventBusName *string } -func (rule *CloudWatchEventsRule) Remove(_ context.Context) error { - _, err := rule.svc.DeleteRule(&cloudwatchevents.DeleteRuleInput{ - Name: rule.name, - EventBusName: rule.busName, +func (r *CloudWatchEventsRule) Remove(_ context.Context) error { + _, err := r.svc.DeleteRule(&cloudwatchevents.DeleteRuleInput{ + Name: r.Name, + EventBusName: r.EventBusName, Force: aws.Bool(true), }) return err } -func (rule *CloudWatchEventsRule) String() string { +func (r *CloudWatchEventsRule) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *CloudWatchEventsRule) String() string { // TODO: remove Rule:, mark as breaking change for filters - return fmt.Sprintf("Rule: %s", *rule.name) + return fmt.Sprintf("Rule: %s", *r.Name) } diff --git a/resources/configservice-configurationrecorders.go b/resources/configservice-configurationrecorder.go similarity index 71% rename from resources/configservice-configurationrecorders.go rename to resources/configservice-configurationrecorder.go index 4739795f..0eb32f37 100644 --- a/resources/configservice-configurationrecorders.go +++ b/resources/configservice-configurationrecorder.go @@ -7,6 +7,7 @@ import ( "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" ) @@ -37,8 +38,8 @@ func (l *ConfigServiceConfigurationRecorderLister) List(_ context.Context, o int resources := make([]resource.Resource, 0) for _, configurationRecorder := range resp.ConfigurationRecorders { resources = append(resources, &ConfigServiceConfigurationRecorder{ - svc: svc, - configurationRecorderName: configurationRecorder.Name, + svc: svc, + Name: configurationRecorder.Name, }) } @@ -46,18 +47,22 @@ func (l *ConfigServiceConfigurationRecorderLister) List(_ context.Context, o int } type ConfigServiceConfigurationRecorder struct { - svc *configservice.ConfigService - configurationRecorderName *string + svc *configservice.ConfigService + Name *string } -func (f *ConfigServiceConfigurationRecorder) Remove(_ context.Context) error { - _, err := f.svc.DeleteConfigurationRecorder(&configservice.DeleteConfigurationRecorderInput{ - ConfigurationRecorderName: f.configurationRecorderName, +func (r *ConfigServiceConfigurationRecorder) Remove(_ context.Context) error { + _, err := r.svc.DeleteConfigurationRecorder(&configservice.DeleteConfigurationRecorderInput{ + ConfigurationRecorderName: r.Name, }) return err } -func (f *ConfigServiceConfigurationRecorder) String() string { - return *f.configurationRecorderName +func (r *ConfigServiceConfigurationRecorder) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *ConfigServiceConfigurationRecorder) String() string { + return *r.Name } diff --git a/resources/configservice-deliverychannels.go b/resources/configservice-deliverychannel.go similarity index 70% rename from resources/configservice-deliverychannels.go rename to resources/configservice-deliverychannel.go index 8f12ad0d..1ba6c998 100644 --- a/resources/configservice-deliverychannels.go +++ b/resources/configservice-deliverychannel.go @@ -7,6 +7,7 @@ import ( "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" ) @@ -25,7 +26,7 @@ type ConfigServiceDeliveryChannelLister struct{} func (l *ConfigServiceDeliveryChannelLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { opts := o.(*nuke.ListerOpts) - + resources := make([]resource.Resource, 0) svc := configservice.New(opts.Session) params := &configservice.DescribeDeliveryChannelsInput{} @@ -34,11 +35,10 @@ func (l *ConfigServiceDeliveryChannelLister) List(_ context.Context, o interface return nil, err } - resources := make([]resource.Resource, 0) for _, deliveryChannel := range resp.DeliveryChannels { resources = append(resources, &ConfigServiceDeliveryChannel{ - svc: svc, - deliveryChannelName: deliveryChannel.Name, + svc: svc, + Name: deliveryChannel.Name, }) } @@ -46,18 +46,22 @@ func (l *ConfigServiceDeliveryChannelLister) List(_ context.Context, o interface } type ConfigServiceDeliveryChannel struct { - svc *configservice.ConfigService - deliveryChannelName *string + svc *configservice.ConfigService + Name *string } -func (f *ConfigServiceDeliveryChannel) Remove(_ context.Context) error { - _, err := f.svc.DeleteDeliveryChannel(&configservice.DeleteDeliveryChannelInput{ - DeliveryChannelName: f.deliveryChannelName, +func (r *ConfigServiceDeliveryChannel) Remove(_ context.Context) error { + _, err := r.svc.DeleteDeliveryChannel(&configservice.DeleteDeliveryChannelInput{ + DeliveryChannelName: r.Name, }) return err } -func (f *ConfigServiceDeliveryChannel) String() string { - return *f.deliveryChannelName +func (r *ConfigServiceDeliveryChannel) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *ConfigServiceDeliveryChannel) String() string { + return *r.Name } diff --git a/resources/dax-clusters.go b/resources/dax-cluster.go similarity index 74% rename from resources/dax-clusters.go rename to resources/dax-cluster.go index 1a8c6dc3..6a9ab96b 100644 --- a/resources/dax-clusters.go +++ b/resources/dax-cluster.go @@ -8,6 +8,7 @@ import ( "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" ) @@ -46,8 +47,8 @@ func (l *DAXClusterLister) List(_ context.Context, o interface{}) ([]resource.Re for _, cluster := range output.Clusters { resources = append(resources, &DAXCluster{ - svc: svc, - clusterName: cluster.ClusterName, + svc: svc, + Name: cluster.ClusterName, }) } @@ -62,18 +63,22 @@ func (l *DAXClusterLister) List(_ context.Context, o interface{}) ([]resource.Re } type DAXCluster struct { - svc *dax.DAX - clusterName *string + svc *dax.DAX + Name *string } -func (f *DAXCluster) Remove(_ context.Context) error { - _, err := f.svc.DeleteCluster(&dax.DeleteClusterInput{ - ClusterName: f.clusterName, +func (r *DAXCluster) Remove(_ context.Context) error { + _, err := r.svc.DeleteCluster(&dax.DeleteClusterInput{ + ClusterName: r.Name, }) return err } -func (f *DAXCluster) String() string { - return *f.clusterName +func (r *DAXCluster) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *DAXCluster) String() string { + return *r.Name } diff --git a/resources/dax-parametergroups.go b/resources/dax-parameter-group.go similarity index 62% rename from resources/dax-parametergroups.go rename to resources/dax-parameter-group.go index 89fb3fed..ce833a16 100644 --- a/resources/dax-parametergroups.go +++ b/resources/dax-parameter-group.go @@ -2,7 +2,7 @@ package resources import ( "context" - + "fmt" "strings" "github.com/aws/aws-sdk-go/aws" @@ -10,15 +10,11 @@ import ( "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" ) -type DAXParameterGroup struct { - svc *dax.DAX - parameterGroupName *string -} - const DAXParameterGroupResource = "DAXParameterGroup" func init() { @@ -48,13 +44,10 @@ func (l *DAXParameterGroupLister) List(_ context.Context, o interface{}) ([]reso } for _, parameterGroup := range output.ParameterGroups { - // ensure default is not deleted - if !strings.Contains(*parameterGroup.ParameterGroupName, "default") { - resources = append(resources, &DAXParameterGroup{ - svc: svc, - parameterGroupName: parameterGroup.ParameterGroupName, - }) - } + resources = append(resources, &DAXParameterGroup{ + svc: svc, + Name: parameterGroup.ParameterGroupName, + }) } if output.NextToken == nil { @@ -67,14 +60,31 @@ func (l *DAXParameterGroupLister) List(_ context.Context, o interface{}) ([]reso return resources, nil } -func (f *DAXParameterGroup) Remove(_ context.Context) error { - _, err := f.svc.DeleteParameterGroup(&dax.DeleteParameterGroupInput{ - ParameterGroupName: f.parameterGroupName, +type DAXParameterGroup struct { + svc *dax.DAX + Name *string +} + +func (r *DAXParameterGroup) Filter() error { + if strings.Contains(*r.Name, "default") { //nolint:goconst,nolintlint + return fmt.Errorf("unable to delete default") + } + + return nil +} + +func (r *DAXParameterGroup) Remove(_ context.Context) error { + _, err := r.svc.DeleteParameterGroup(&dax.DeleteParameterGroupInput{ + ParameterGroupName: r.Name, }) return err } -func (f *DAXParameterGroup) String() string { - return *f.parameterGroupName +func (r *DAXParameterGroup) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *DAXParameterGroup) String() string { + return *r.Name } diff --git a/resources/dax-subnetgroups.go b/resources/dax-subnet-group.go similarity index 70% rename from resources/dax-subnetgroups.go rename to resources/dax-subnet-group.go index c4021359..704a63fc 100644 --- a/resources/dax-subnetgroups.go +++ b/resources/dax-subnet-group.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "github.com/aws/aws-sdk-go/aws" @@ -10,6 +9,7 @@ import ( "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" ) @@ -44,8 +44,8 @@ func (l *DAXSubnetGroupLister) List(_ context.Context, o interface{}) ([]resourc for _, subnet := range output.SubnetGroups { resources = append(resources, &DAXSubnetGroup{ - svc: svc, - subnetGroupName: subnet.SubnetGroupName, + svc: svc, + Name: subnet.SubnetGroupName, }) } @@ -60,25 +60,29 @@ func (l *DAXSubnetGroupLister) List(_ context.Context, o interface{}) ([]resourc } type DAXSubnetGroup struct { - svc *dax.DAX - subnetGroupName *string + svc *dax.DAX + Name *string } -func (f *DAXSubnetGroup) Filter() error { - if *f.subnetGroupName == "default" { +func (r *DAXSubnetGroup) Filter() error { + if *r.Name == "default" { //nolint:goconst,nolintlint return fmt.Errorf("cannot delete default DAX Subnet group") } return nil } -func (f *DAXSubnetGroup) Remove(_ context.Context) error { - _, err := f.svc.DeleteSubnetGroup(&dax.DeleteSubnetGroupInput{ - SubnetGroupName: f.subnetGroupName, +func (r *DAXSubnetGroup) Remove(_ context.Context) error { + _, err := r.svc.DeleteSubnetGroup(&dax.DeleteSubnetGroupInput{ + SubnetGroupName: r.Name, }) return err } -func (f *DAXSubnetGroup) String() string { - return *f.subnetGroupName +func (r *DAXSubnetGroup) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *DAXSubnetGroup) String() string { + return *r.Name } diff --git a/resources/iam-saml-provider.go b/resources/iam-saml-provider.go index cf1d8efb..86cacbf7 100644 --- a/resources/iam-saml-provider.go +++ b/resources/iam-saml-provider.go @@ -2,12 +2,16 @@ package resources import ( "context" + "time" "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam/iamiface" - "github.com/ekristen/aws-nuke/v3/pkg/nuke" + "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" + + "github.com/ekristen/aws-nuke/v3/pkg/nuke" ) const IAMSAMLProviderResource = "IAMSAMLProvider" @@ -36,8 +40,9 @@ func (l *IAMSAMLProviderLister) List(_ context.Context, o interface{}) ([]resour for _, out := range resp.SAMLProviderList { resources = append(resources, &IAMSAMLProvider{ - svc: svc, - arn: *out.Arn, + svc: svc, + ARN: out.Arn, + CreateDate: out.CreateDate, }) } @@ -45,13 +50,14 @@ func (l *IAMSAMLProviderLister) List(_ context.Context, o interface{}) ([]resour } type IAMSAMLProvider struct { - svc iamiface.IAMAPI - arn string + svc iamiface.IAMAPI + ARN *string + CreateDate *time.Time } -func (e *IAMSAMLProvider) Remove(_ context.Context) error { - _, err := e.svc.DeleteSAMLProvider(&iam.DeleteSAMLProviderInput{ - SAMLProviderArn: &e.arn, +func (r *IAMSAMLProvider) Remove(_ context.Context) error { + _, err := r.svc.DeleteSAMLProvider(&iam.DeleteSAMLProviderInput{ + SAMLProviderArn: r.ARN, }) if err != nil { return err @@ -60,6 +66,10 @@ func (e *IAMSAMLProvider) Remove(_ context.Context) error { return nil } -func (e *IAMSAMLProvider) String() string { - return e.arn +func (r *IAMSAMLProvider) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *IAMSAMLProvider) String() string { + return *r.ARN } diff --git a/resources/iam-saml-provider_mock_test.go b/resources/iam-saml-provider_mock_test.go index 45a48e40..bae5eb56 100644 --- a/resources/iam-saml-provider_mock_test.go +++ b/resources/iam-saml-provider_mock_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + "github.com/gotidy/ptr" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" @@ -21,11 +23,11 @@ func Test_Mock_IAMSAMLProvider_Remove(t *testing.T) { iamSAMLProvider := IAMSAMLProvider{ svc: mockIAM, - arn: "arn:mock-saml-provider-foobar", + ARN: ptr.String("arn:mock-saml-provider-foobar"), } mockIAM.EXPECT().DeleteSAMLProvider(gomock.Eq(&iam.DeleteSAMLProviderInput{ - SAMLProviderArn: &iamSAMLProvider.arn, + SAMLProviderArn: iamSAMLProvider.ARN, })).Return(&iam.DeleteSAMLProviderOutput{}, nil) err := iamSAMLProvider.Remove(context.TODO()) diff --git a/resources/s3-bucket.go b/resources/s3-bucket.go index cf9efe50..127786bc 100644 --- a/resources/s3-bucket.go +++ b/resources/s3-bucket.go @@ -67,7 +67,13 @@ func (l *S3BucketLister) List(_ context.Context, o interface{}) ([]resource.Reso Bucket: &newBucket.name, }) if err != nil { - logrus.WithError(err).Warn("failed to get object lock configuration") + // check if aws error is NoSuchObjectLockConfiguration + var aerr awserr.Error + if errors.As(err, &aerr) { + if aerr.Code() != "ObjectLockConfigurationNotFoundError" { + logrus.WithError(err).Warn("unknown failure during get object lock configuration") + } + } } if lockCfg != nil && lockCfg.ObjectLockConfiguration != nil { diff --git a/resources/sns-subscriptions.go b/resources/sns-subscription.go similarity index 66% rename from resources/sns-subscriptions.go rename to resources/sns-subscription.go index 73c397a1..654223d2 100644 --- a/resources/sns-subscriptions.go +++ b/resources/sns-subscription.go @@ -2,13 +2,13 @@ package resources import ( "context" - "fmt" "github.com/aws/aws-sdk-go/service/sns" "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" ) @@ -42,9 +42,10 @@ func (l *SNSSubscriptionLister) List(_ context.Context, o interface{}) ([]resour for _, subscription := range resp.Subscriptions { if *subscription.SubscriptionArn != "PendingConfirmation" { resources = append(resources, &SNSSubscription{ - svc: svc, - id: subscription.SubscriptionArn, - name: subscription.Owner, + svc: svc, + ARN: subscription.SubscriptionArn, + Owner: subscription.Owner, + TopicARN: subscription.TopicArn, }) } } @@ -60,18 +61,23 @@ func (l *SNSSubscriptionLister) List(_ context.Context, o interface{}) ([]resour } type SNSSubscription struct { - svc *sns.SNS - id *string - name *string + svc *sns.SNS + ARN *string + Owner *string + TopicARN *string } -func (subs *SNSSubscription) Remove(_ context.Context) error { - _, err := subs.svc.Unsubscribe(&sns.UnsubscribeInput{ - SubscriptionArn: subs.id, +func (r *SNSSubscription) Remove(_ context.Context) error { + _, err := r.svc.Unsubscribe(&sns.UnsubscribeInput{ + SubscriptionArn: r.ARN, }) return err } -func (subs *SNSSubscription) String() string { - return fmt.Sprintf("Owner: %s ARN: %s", *subs.name, *subs.id) +func (r *SNSSubscription) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *SNSSubscription) String() string { + return fmt.Sprintf("Owner: %s ARN: %s", *r.Owner, *r.ARN) }