From bbf9db87dd3b9b87a7b19528748cb209a8346a93 Mon Sep 17 00:00:00 2001 From: Sherd White Date: Wed, 7 Aug 2024 10:14:25 -0500 Subject: [PATCH 1/5] feat(resource): adding athena data catalogs and prepared statements This PR adds support for AWS athena data catalogs and prepared statements. --- resources/athena-data-catalogs.go | 77 ++++++++++++++++++++++++ resources/athena-prepared-statements.go | 80 +++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 resources/athena-data-catalogs.go create mode 100644 resources/athena-prepared-statements.go diff --git a/resources/athena-data-catalogs.go b/resources/athena-data-catalogs.go new file mode 100644 index 00000000..c59e833e --- /dev/null +++ b/resources/athena-data-catalogs.go @@ -0,0 +1,77 @@ +package resources + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/athena" + "github.com/rebuy-de/aws-nuke/v2/pkg/types" +) + +type AthenaDataCatalog struct { + svc *athena.Athena + name *string +} + +func init() { + register("AthenaDataCatalog", ListAthenaDataCatalogs) +} + +func ListAthenaDataCatalogs(sess *session.Session) ([]Resource, error) { + svc := athena.New(sess) + resources := []Resource{} + + params := &athena.ListDataCatalogsInput{ + MaxResults: aws.Int64(50), + } + + for { + output, err := svc.ListDataCatalogs(params) + if err != nil { + return nil, err + } + + for _, catalog := range output.DataCatalogsSummary { + resources = append(resources, &AthenaDataCatalog{ + svc: svc, + name: catalog.CatalogName, + }) + } + + if output.NextToken == nil { + break + } + + params.NextToken = output.NextToken + } + + return resources, nil +} + +func (f *AthenaDataCatalog) Properties() types.Properties { + properties := types.NewProperties() + properties.Set("Name", f.name) + + return properties +} + +func (f *AthenaDataCatalog) Remove() error { + + _, err := f.svc.DeleteDataCatalog(&athena.DeleteDataCatalogInput{ + Name: f.name, + }) + + return err +} + +func (f *AthenaDataCatalog) Filter() error { + if *f.name == "AwsDataCatalog" { + return fmt.Errorf("cannot delete default data source") + } + return nil +} + +func (f *AthenaDataCatalog) String() string { + return *f.name +} diff --git a/resources/athena-prepared-statements.go b/resources/athena-prepared-statements.go new file mode 100644 index 00000000..0f0593d7 --- /dev/null +++ b/resources/athena-prepared-statements.go @@ -0,0 +1,80 @@ +package resources + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/athena" + "github.com/rebuy-de/aws-nuke/v2/pkg/types" +) + +type AthenaPreparedStatement struct { + svc *athena.Athena + workGroup *string + name *string +} + +func init() { + register("AthenaPreparedStatement", ListAthenaPreparedStatements) +} + +func ListAthenaPreparedStatements(sess *session.Session) ([]Resource, error) { + svc := athena.New(sess) + resources := []Resource{} + + workgroups, err := svc.ListWorkGroups(&athena.ListWorkGroupsInput{}) + if err != nil { + return nil, err + } + + for _, workgroup := range workgroups.WorkGroups { + params := &athena.ListPreparedStatementsInput{ + WorkGroup: workgroup.Name, + MaxResults: aws.Int64(50), + } + + for { + output, err := svc.ListPreparedStatements(params) + if err != nil { + return nil, err + } + + for _, statement := range output.PreparedStatements { + resources = append(resources, &AthenaPreparedStatement{ + svc: svc, + workGroup: workgroup.Name, + name: statement.StatementName, + }) + } + + if output.NextToken == nil { + break + } + + params.NextToken = output.NextToken + } + } + + return resources, nil +} + +func (f *AthenaPreparedStatement) Properties() types.Properties { + properties := types.NewProperties() + properties.Set("StatementName", f.name) + properties.Set("WorkGroup", f.workGroup) + + return properties +} + +func (f *AthenaPreparedStatement) Remove() error { + + _, err := f.svc.DeletePreparedStatement(&athena.DeletePreparedStatementInput{ + StatementName: f.name, + WorkGroup: f.workGroup, + }) + + return err +} + +func (f *AthenaPreparedStatement) String() string { + return *f.name +} From c98ab72f8da6b3a7d67673f98e6eed4a35b91e89 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Sat, 31 Aug 2024 17:13:47 -0600 Subject: [PATCH 2/5] refactor(athena-data-catalog): standardize to libnuke format --- resources/athena-data-catalog.go | 89 +++++++++++++++++++++++++++++++ resources/athena-data-catalogs.go | 77 -------------------------- 2 files changed, 89 insertions(+), 77 deletions(-) create mode 100644 resources/athena-data-catalog.go delete mode 100644 resources/athena-data-catalogs.go diff --git a/resources/athena-data-catalog.go b/resources/athena-data-catalog.go new file mode 100644 index 00000000..f361f6e8 --- /dev/null +++ b/resources/athena-data-catalog.go @@ -0,0 +1,89 @@ +package resources + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go/aws" + + "github.com/aws/aws-sdk-go/service/athena" + + "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 AthenaDataCatalogResource = "AthenaDataCatalog" + +func init() { + registry.Register(®istry.Registration{ + Name: AthenaDataCatalogResource, + Scope: nuke.Account, + Lister: &AthenaDataCatalogLister{}, + }) +} + +type AthenaDataCatalogLister struct{} + +func (l *AthenaDataCatalogLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { + opts := o.(*nuke.ListerOpts) + + svc := athena.New(opts.Session) + resources := make([]resource.Resource, 0) + + params := &athena.ListDataCatalogsInput{ + MaxResults: aws.Int64(50), + } + + for { + output, err := svc.ListDataCatalogs(params) + if err != nil { + return nil, err + } + + for _, catalog := range output.DataCatalogsSummary { + resources = append(resources, &AthenaDataCatalog{ + svc: svc, + Name: catalog.CatalogName, + }) + } + + if output.NextToken == nil { + break + } + + params.NextToken = output.NextToken + } + + return resources, nil +} + +type AthenaDataCatalog struct { + svc *athena.Athena + Name *string +} + +func (r *AthenaDataCatalog) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *AthenaDataCatalog) Remove(_ context.Context) error { + _, err := r.svc.DeleteDataCatalog(&athena.DeleteDataCatalogInput{ + Name: r.Name, + }) + + return err +} + +func (r *AthenaDataCatalog) Filter() error { + if *r.Name == "AwsDataCatalog" { + return fmt.Errorf("cannot delete default data source") + } + return nil +} + +func (r *AthenaDataCatalog) String() string { + return *r.Name +} diff --git a/resources/athena-data-catalogs.go b/resources/athena-data-catalogs.go deleted file mode 100644 index c59e833e..00000000 --- a/resources/athena-data-catalogs.go +++ /dev/null @@ -1,77 +0,0 @@ -package resources - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/athena" - "github.com/rebuy-de/aws-nuke/v2/pkg/types" -) - -type AthenaDataCatalog struct { - svc *athena.Athena - name *string -} - -func init() { - register("AthenaDataCatalog", ListAthenaDataCatalogs) -} - -func ListAthenaDataCatalogs(sess *session.Session) ([]Resource, error) { - svc := athena.New(sess) - resources := []Resource{} - - params := &athena.ListDataCatalogsInput{ - MaxResults: aws.Int64(50), - } - - for { - output, err := svc.ListDataCatalogs(params) - if err != nil { - return nil, err - } - - for _, catalog := range output.DataCatalogsSummary { - resources = append(resources, &AthenaDataCatalog{ - svc: svc, - name: catalog.CatalogName, - }) - } - - if output.NextToken == nil { - break - } - - params.NextToken = output.NextToken - } - - return resources, nil -} - -func (f *AthenaDataCatalog) Properties() types.Properties { - properties := types.NewProperties() - properties.Set("Name", f.name) - - return properties -} - -func (f *AthenaDataCatalog) Remove() error { - - _, err := f.svc.DeleteDataCatalog(&athena.DeleteDataCatalogInput{ - Name: f.name, - }) - - return err -} - -func (f *AthenaDataCatalog) Filter() error { - if *f.name == "AwsDataCatalog" { - return fmt.Errorf("cannot delete default data source") - } - return nil -} - -func (f *AthenaDataCatalog) String() string { - return *f.name -} From 76fd95b30cd2cffc19e6c153d906dbc86504bcfd Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Sat, 31 Aug 2024 17:13:58 -0600 Subject: [PATCH 3/5] refactor(athena-prepared-statement): standardize to libnuke format --- resources/athena-prepared-statement.go | 92 +++++++++++++++++++++++++ resources/athena-prepared-statements.go | 80 --------------------- 2 files changed, 92 insertions(+), 80 deletions(-) create mode 100644 resources/athena-prepared-statement.go delete mode 100644 resources/athena-prepared-statements.go diff --git a/resources/athena-prepared-statement.go b/resources/athena-prepared-statement.go new file mode 100644 index 00000000..4e591f57 --- /dev/null +++ b/resources/athena-prepared-statement.go @@ -0,0 +1,92 @@ +package resources + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + + "github.com/aws/aws-sdk-go/service/athena" + + "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 AthenaPreparedStatementResource = "AthenaPreparedStatement" + +func init() { + registry.Register(®istry.Registration{ + Name: AthenaPreparedStatementResource, + Scope: nuke.Account, + Lister: &AthenaPreparedStatementLister{}, + }) +} + +type AthenaPreparedStatementLister struct{} + +func (l *AthenaPreparedStatementLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { + opts := o.(*nuke.ListerOpts) + + svc := athena.New(opts.Session) + resources := make([]resource.Resource, 0) + + workgroups, err := svc.ListWorkGroups(&athena.ListWorkGroupsInput{}) + if err != nil { + return nil, err + } + + for _, workgroup := range workgroups.WorkGroups { + params := &athena.ListPreparedStatementsInput{ + WorkGroup: workgroup.Name, + MaxResults: aws.Int64(50), + } + + for { + output, err := svc.ListPreparedStatements(params) + if err != nil { + return nil, err + } + + for _, statement := range output.PreparedStatements { + resources = append(resources, &AthenaPreparedStatement{ + svc: svc, + Name: statement.StatementName, + WorkGroup: workgroup.Name, + }) + } + + if output.NextToken == nil { + break + } + + params.NextToken = output.NextToken + } + } + + return resources, nil +} + +type AthenaPreparedStatement struct { + svc *athena.Athena + Name *string + WorkGroup *string +} + +func (r *AthenaPreparedStatement) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + +func (r *AthenaPreparedStatement) Remove(_ context.Context) error { + _, err := r.svc.DeletePreparedStatement(&athena.DeletePreparedStatementInput{ + StatementName: r.Name, + WorkGroup: r.WorkGroup, + }) + + return err +} + +func (r *AthenaPreparedStatement) String() string { + return *r.Name +} diff --git a/resources/athena-prepared-statements.go b/resources/athena-prepared-statements.go deleted file mode 100644 index 0f0593d7..00000000 --- a/resources/athena-prepared-statements.go +++ /dev/null @@ -1,80 +0,0 @@ -package resources - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/athena" - "github.com/rebuy-de/aws-nuke/v2/pkg/types" -) - -type AthenaPreparedStatement struct { - svc *athena.Athena - workGroup *string - name *string -} - -func init() { - register("AthenaPreparedStatement", ListAthenaPreparedStatements) -} - -func ListAthenaPreparedStatements(sess *session.Session) ([]Resource, error) { - svc := athena.New(sess) - resources := []Resource{} - - workgroups, err := svc.ListWorkGroups(&athena.ListWorkGroupsInput{}) - if err != nil { - return nil, err - } - - for _, workgroup := range workgroups.WorkGroups { - params := &athena.ListPreparedStatementsInput{ - WorkGroup: workgroup.Name, - MaxResults: aws.Int64(50), - } - - for { - output, err := svc.ListPreparedStatements(params) - if err != nil { - return nil, err - } - - for _, statement := range output.PreparedStatements { - resources = append(resources, &AthenaPreparedStatement{ - svc: svc, - workGroup: workgroup.Name, - name: statement.StatementName, - }) - } - - if output.NextToken == nil { - break - } - - params.NextToken = output.NextToken - } - } - - return resources, nil -} - -func (f *AthenaPreparedStatement) Properties() types.Properties { - properties := types.NewProperties() - properties.Set("StatementName", f.name) - properties.Set("WorkGroup", f.workGroup) - - return properties -} - -func (f *AthenaPreparedStatement) Remove() error { - - _, err := f.svc.DeletePreparedStatement(&athena.DeletePreparedStatementInput{ - StatementName: f.name, - WorkGroup: f.workGroup, - }) - - return err -} - -func (f *AthenaPreparedStatement) String() string { - return *f.name -} From afd13eda79f443758570fe37cb55f6d9d3416de9 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Sat, 31 Aug 2024 17:15:56 -0600 Subject: [PATCH 4/5] refactor(athena-work-group): rearrange struct location, rename pointers to standard --- ...na-work-groups.go => athena-work-group.go} | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) rename resources/{athena-work-groups.go => athena-work-group.go} (80%) diff --git a/resources/athena-work-groups.go b/resources/athena-work-group.go similarity index 80% rename from resources/athena-work-groups.go rename to resources/athena-work-group.go index 58c5675d..6b275e79 100644 --- a/resources/athena-work-groups.go +++ b/resources/athena-work-group.go @@ -31,12 +31,6 @@ func init() { type AthenaWorkGroupLister struct{} -type AthenaWorkGroup struct { - svc *athena.Athena - name *string - arn *string -} - func (l *AthenaWorkGroupLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { opts := o.(*nuke.ListerOpts) @@ -84,15 +78,21 @@ func (l *AthenaWorkGroupLister) List(_ context.Context, o interface{}) ([]resour return resources, err } -func (a *AthenaWorkGroup) Remove(_ context.Context) error { +type AthenaWorkGroup struct { + svc *athena.Athena + name *string + arn *string +} + +func (r *AthenaWorkGroup) Remove(_ context.Context) error { // Primary WorkGroup cannot be deleted, - // but we can reset it to a clean state - if *a.name == "primary" { + // but we can reset it to r clean state + if *r.name == "primary" { // TODO: pass logger via ListerOpts instead of using global logrus.Info("Primary Athena WorkGroup may not be deleted. Resetting configuration only.") // Reset the configuration to its default state - _, err := a.svc.UpdateWorkGroup(&athena.UpdateWorkGroupInput{ + _, err := r.svc.UpdateWorkGroup(&athena.UpdateWorkGroupInput{ // See https://docs.aws.amazon.com/athena/latest/APIReference/API_WorkGroupConfigurationUpdates.html // for documented defaults ConfigurationUpdates: &athena.WorkGroupConfigurationUpdates{ @@ -106,15 +106,15 @@ func (a *AthenaWorkGroup) Remove(_ context.Context) error { }, }, Description: aws.String(""), - WorkGroup: a.name, + WorkGroup: r.name, }) if err != nil { return err } // Remove any tags - wgTagsRes, err := a.svc.ListTagsForResource(&athena.ListTagsForResourceInput{ - ResourceARN: a.arn, + wgTagsRes, err := r.svc.ListTagsForResource(&athena.ListTagsForResourceInput{ + ResourceARN: r.arn, }) if err != nil { return err @@ -125,8 +125,8 @@ func (a *AthenaWorkGroup) Remove(_ context.Context) error { tagKeys = append(tagKeys, tag.Key) } - _, err = a.svc.UntagResource(&athena.UntagResourceInput{ - ResourceARN: a.arn, + _, err = r.svc.UntagResource(&athena.UntagResourceInput{ + ResourceARN: r.arn, TagKeys: tagKeys, }) if err != nil { @@ -136,35 +136,35 @@ func (a *AthenaWorkGroup) Remove(_ context.Context) error { return nil } - _, err := a.svc.DeleteWorkGroup(&athena.DeleteWorkGroupInput{ + _, err := r.svc.DeleteWorkGroup(&athena.DeleteWorkGroupInput{ RecursiveDeleteOption: aws.Bool(true), - WorkGroup: a.name, + WorkGroup: r.name, }) return err } -func (a *AthenaWorkGroup) Filter() error { +func (r *AthenaWorkGroup) Filter() error { // If this is the primary work group, // check if it's already had its configuration reset - if *a.name == "primary" { + if *r.name == "primary" { // Get workgroup configuration - wgConfigRes, err := a.svc.GetWorkGroup(&athena.GetWorkGroupInput{ - WorkGroup: a.name, + wgConfigRes, err := r.svc.GetWorkGroup(&athena.GetWorkGroupInput{ + WorkGroup: r.name, }) if err != nil { return err } // Get workgroup tags - wgTagsRes, err := a.svc.ListTagsForResource(&athena.ListTagsForResourceInput{ - ResourceARN: a.arn, + wgTagsRes, err := r.svc.ListTagsForResource(&athena.ListTagsForResourceInput{ + ResourceARN: r.arn, }) if err != nil { return err } - // If the workgroup is already in a "clean" state, then + // If the workgroup is already in r "clean" state, then // don't add it to our plan wgConfig := wgConfigRes.WorkGroup.Configuration isCleanConfig := wgConfig.BytesScannedCutoffPerQuery == nil && @@ -181,12 +181,12 @@ func (a *AthenaWorkGroup) Filter() error { return nil } -func (a *AthenaWorkGroup) Properties() types.Properties { +func (r *AthenaWorkGroup) Properties() types.Properties { return types.NewProperties(). - Set("Name", *a.name). - Set("ARN", *a.arn) + Set("Name", *r.name). + Set("ARN", *r.arn) } -func (a *AthenaWorkGroup) String() string { - return *a.name +func (r *AthenaWorkGroup) String() string { + return *r.name } From 37f6f826df50a04b957f1e3371201a90201a4e9c Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Sat, 31 Aug 2024 17:16:37 -0600 Subject: [PATCH 5/5] refactor(athena-named-query): rearrange struct location, rename pointers to standard --- ...named-queries.go => athena-named-query.go} | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) rename resources/{athena-named-queries.go => athena-named-query.go} (86%) diff --git a/resources/athena-named-queries.go b/resources/athena-named-query.go similarity index 86% rename from resources/athena-named-queries.go rename to resources/athena-named-query.go index b0b1a065..ed011f69 100644 --- a/resources/athena-named-queries.go +++ b/resources/athena-named-query.go @@ -24,11 +24,6 @@ func init() { type AthenaNamedQueryLister struct{} -type AthenaNamedQuery struct { - svc *athena.Athena - id *string -} - func (l *AthenaNamedQueryLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { opts := o.(*nuke.ListerOpts) @@ -76,19 +71,24 @@ func (l *AthenaNamedQueryLister) List(_ context.Context, o interface{}) ([]resou return resources, err } -func (a *AthenaNamedQuery) Remove(_ context.Context) error { - _, err := a.svc.DeleteNamedQuery(&athena.DeleteNamedQueryInput{ - NamedQueryId: a.id, +type AthenaNamedQuery struct { + svc *athena.Athena + id *string +} + +func (r *AthenaNamedQuery) Remove(_ context.Context) error { + _, err := r.svc.DeleteNamedQuery(&athena.DeleteNamedQueryInput{ + NamedQueryId: r.id, }) return err } -func (a *AthenaNamedQuery) Properties() types.Properties { +func (r *AthenaNamedQuery) Properties() types.Properties { return types.NewProperties(). - Set("Id", *a.id) + Set("Id", *r.id) } -func (a *AthenaNamedQuery) String() string { - return *a.id +func (r *AthenaNamedQuery) String() string { + return *r.id }