From 5bfaf103bdf099567e4e31d8f10d5d59ee990eb3 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 17:19:40 -0700 Subject: [PATCH 01/10] refactor(sfn-state-machine): standardization --- .../{sfn-statemachines.go => sfn-state-machine.go} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename resources/{sfn-statemachines.go => sfn-state-machine.go} (85%) diff --git a/resources/sfn-statemachines.go b/resources/sfn-state-machine.go similarity index 85% rename from resources/sfn-statemachines.go rename to resources/sfn-state-machine.go index ca38e0bd..0522e5ec 100644 --- a/resources/sfn-statemachines.go +++ b/resources/sfn-state-machine.go @@ -63,14 +63,14 @@ type SFNStateMachine struct { ARN *string } -func (f *SFNStateMachine) Remove(_ context.Context) error { - _, err := f.svc.DeleteStateMachine(&sfn.DeleteStateMachineInput{ - StateMachineArn: f.ARN, +func (r *SFNStateMachine) Remove(_ context.Context) error { + _, err := r.svc.DeleteStateMachine(&sfn.DeleteStateMachineInput{ + StateMachineArn: r.ARN, }) return err } -func (f *SFNStateMachine) String() string { - return *f.ARN +func (r *SFNStateMachine) String() string { + return *r.ARN } From 01d94f8b62bf548647451be2642b22c207f1f391 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 17:22:55 -0700 Subject: [PATCH 02/10] feat(sfn-state-machine): new properties, tags, name, type, creationdate --- resources/sfn-state-machine.go | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/resources/sfn-state-machine.go b/resources/sfn-state-machine.go index 0522e5ec..a6cf1458 100644 --- a/resources/sfn-state-machine.go +++ b/resources/sfn-state-machine.go @@ -2,6 +2,8 @@ package resources import ( "context" + "github.com/ekristen/libnuke/pkg/types" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/sfn" @@ -42,9 +44,23 @@ func (l *SFNStateMachineLister) List(_ context.Context, o interface{}) ([]resour } for _, stateMachine := range output.StateMachines { + var resourceTags []*sfn.Tag + tags, err := svc.ListTagsForResource(&sfn.ListTagsForResourceInput{ + ResourceArn: stateMachine.StateMachineArn, + }) + if err != nil { + opts.Logger.WithError(err).Error("unable to list state machine tags") + } else { + resourceTags = tags.Tags + } + resources = append(resources, &SFNStateMachine{ - svc: svc, - ARN: stateMachine.StateMachineArn, + svc: svc, + ARN: stateMachine.StateMachineArn, + Name: stateMachine.Name, + Type: stateMachine.Type, + CreationDate: stateMachine.CreationDate, + Tags: resourceTags, }) } @@ -59,8 +75,12 @@ func (l *SFNStateMachineLister) List(_ context.Context, o interface{}) ([]resour } type SFNStateMachine struct { - svc *sfn.SFN - ARN *string + svc *sfn.SFN + ARN *string `description:"The Amazon Resource Name (ARN) that identifies the state machine."` + Name *string `description:"The name of the state machine."` + Type *string `description:"The type of the state machine."` + CreationDate *time.Time `description:"The date the state machine was created."` + Tags []*sfn.Tag `description:"The tags associated with the state machine."` } func (r *SFNStateMachine) Remove(_ context.Context) error { @@ -71,6 +91,10 @@ func (r *SFNStateMachine) Remove(_ context.Context) error { return err } +func (r *SFNStateMachine) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) +} + func (r *SFNStateMachine) String() string { return *r.ARN } From c2864f5e7672b67fc96465b88611347945715b5b Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 17:23:55 -0700 Subject: [PATCH 03/10] docs(sfn-state-machine): updating properties --- docs/resources/sfn-state-machine.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/resources/sfn-state-machine.md b/docs/resources/sfn-state-machine.md index 0fd40a6f..e4e3de89 100644 --- a/docs/resources/sfn-state-machine.md +++ b/docs/resources/sfn-state-machine.md @@ -14,7 +14,12 @@ SFNStateMachine ## Properties -- `ARN`: No Description +- `ARN`: The Amazon Resource Name (ARN) that identifies the state machine. +- `CreationDate`: The date the state machine was created. +- `Name`: The name of the state machine. +- `Type`: The type of the state machine. +- `tag::`: This resource has tags with property `Tags`. These are key/value pairs that are + added as their own property with the prefix of `tag:` (e.g. [tag:example: "value"]) !!! note - Using Properties Properties are what [Filters](../config-filtering.md) are written against in your configuration. You use the property From a5900668aaffc4c2030ac56e903466e64580ecc2 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 17:24:27 -0700 Subject: [PATCH 04/10] chore(golangci-lint): fix goimports --- resources/sfn-state-machine.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/sfn-state-machine.go b/resources/sfn-state-machine.go index a6cf1458..20bbf4e8 100644 --- a/resources/sfn-state-machine.go +++ b/resources/sfn-state-machine.go @@ -2,7 +2,6 @@ package resources import ( "context" - "github.com/ekristen/libnuke/pkg/types" "time" "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" ) From 2791fdba5e8eb512a0d80f46abc8055b32608ee2 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 17:29:42 -0700 Subject: [PATCH 05/10] feat(neptune-cluster): tags and properties --- resources/neptune-clusters.go | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/resources/neptune-clusters.go b/resources/neptune-clusters.go index 7e1c6781..92307b23 100644 --- a/resources/neptune-clusters.go +++ b/resources/neptune-clusters.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" ) @@ -42,9 +43,20 @@ func (l *NeptuneClusterLister) List(_ context.Context, o interface{}) ([]resourc } for _, dbCluster := range output.DBClusters { + var dbTags []*neptune.Tag + tags, err := svc.ListTagsForResource(&neptune.ListTagsForResourceInput{ + ResourceName: dbCluster.DBClusterArn, + }) + if err != nil { + opts.Logger.WithError(err).Warn("failed to list tags for resource") + } else { + dbTags = tags.TagList + } + resources = append(resources, &NeptuneCluster{ - svc: svc, - ID: dbCluster.DBClusterIdentifier, + svc: svc, + ID: dbCluster.DBClusterIdentifier, + Tags: dbTags, }) } @@ -59,8 +71,9 @@ func (l *NeptuneClusterLister) List(_ context.Context, o interface{}) ([]resourc } type NeptuneCluster struct { - svc *neptune.Neptune - ID *string + svc *neptune.Neptune + ID *string + Tags []*neptune.Tag } func (f *NeptuneCluster) Remove(_ context.Context) error { @@ -72,6 +85,10 @@ func (f *NeptuneCluster) Remove(_ context.Context) error { return err } +func (f *NeptuneCluster) Properties() types.Properties { + return types.NewPropertiesFromStruct(f) +} + func (f *NeptuneCluster) String() string { return *f.ID } From 53a2f700f6d70c177beca55226a99ff20fbeb750 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 17:30:06 -0700 Subject: [PATCH 06/10] refactor(neptune-cluster): standardization --- .../{neptune-clusters.go => neptune-cluster.go} | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename resources/{neptune-clusters.go => neptune-cluster.go} (84%) diff --git a/resources/neptune-clusters.go b/resources/neptune-cluster.go similarity index 84% rename from resources/neptune-clusters.go rename to resources/neptune-cluster.go index 92307b23..abdda876 100644 --- a/resources/neptune-clusters.go +++ b/resources/neptune-cluster.go @@ -76,19 +76,19 @@ type NeptuneCluster struct { Tags []*neptune.Tag } -func (f *NeptuneCluster) Remove(_ context.Context) error { - _, err := f.svc.DeleteDBCluster(&neptune.DeleteDBClusterInput{ - DBClusterIdentifier: f.ID, +func (r *NeptuneCluster) Remove(_ context.Context) error { + _, err := r.svc.DeleteDBCluster(&neptune.DeleteDBClusterInput{ + DBClusterIdentifier: r.ID, SkipFinalSnapshot: aws.Bool(true), }) return err } -func (f *NeptuneCluster) Properties() types.Properties { - return types.NewPropertiesFromStruct(f) +func (r *NeptuneCluster) Properties() types.Properties { + return types.NewPropertiesFromStruct(r) } -func (f *NeptuneCluster) String() string { - return *f.ID +func (r *NeptuneCluster) String() string { + return *r.ID } From e3a0fd3e0b5cb13f9bcf57b7d88d22ccd5a9d53c Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 18:01:39 -0700 Subject: [PATCH 07/10] fix(rds-instance): filter out neptune instances --- resources/rds-instances.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resources/rds-instances.go b/resources/rds-instances.go index 7bc0af26..997fd93d 100644 --- a/resources/rds-instances.go +++ b/resources/rds-instances.go @@ -4,6 +4,8 @@ import ( "context" "time" + "github.com/gotidy/ptr" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" @@ -52,6 +54,12 @@ func (l *RDSInstanceLister) List(_ context.Context, o interface{}) ([]resource.R resources := make([]resource.Resource, 0) for _, instance := range resp.DBInstances { + // Note: NeptuneInstance handles Neptune instances + if ptr.ToString(instance.Engine) == "neptune" { + opts.Logger.Debug("skipping neptune instance, it is handled by NeptuneInstance") + continue + } + tags, err := svc.ListTagsForResource(&rds.ListTagsForResourceInput{ ResourceName: instance.DBInstanceArn, }) From 2cc68d015c274566ff2cce8fde9fc6b261568837 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 18:02:05 -0700 Subject: [PATCH 08/10] feat(neptune): support deletion protect, properties, tags --- resources/neptune-cluster.go | 49 +++++++++++++++++++++++---- resources/neptune-instance.go | 62 +++++++++++++++++++++++++++++------ 2 files changed, 94 insertions(+), 17 deletions(-) diff --git a/resources/neptune-cluster.go b/resources/neptune-cluster.go index abdda876..a20abe26 100644 --- a/resources/neptune-cluster.go +++ b/resources/neptune-cluster.go @@ -2,12 +2,16 @@ package resources import ( "context" + "fmt" + + "github.com/gotidy/ptr" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/neptune" "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + libsettings "github.com/ekristen/libnuke/pkg/settings" "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" @@ -21,6 +25,12 @@ func init() { Scope: nuke.Account, Resource: &NeptuneCluster{}, Lister: &NeptuneClusterLister{}, + DependsOn: []string{ + NeptuneInstanceResource, + }, + Settings: []string{ + "DisableDeletionProtection", + }, }) } @@ -54,9 +64,10 @@ func (l *NeptuneClusterLister) List(_ context.Context, o interface{}) ([]resourc } resources = append(resources, &NeptuneCluster{ - svc: svc, - ID: dbCluster.DBClusterIdentifier, - Tags: dbTags, + svc: svc, + ID: dbCluster.DBClusterIdentifier, + Status: dbCluster.Status, + Tags: dbTags, }) } @@ -71,15 +82,39 @@ func (l *NeptuneClusterLister) List(_ context.Context, o interface{}) ([]resourc } type NeptuneCluster struct { - svc *neptune.Neptune - ID *string - Tags []*neptune.Tag + svc *neptune.Neptune + settings *libsettings.Setting + + ID *string + Status *string + Tags []*neptune.Tag +} + +func (r *NeptuneCluster) Settings(settings *libsettings.Setting) { + r.settings = settings +} + +func (r *NeptuneCluster) Filter() error { + if ptr.ToString(r.Status) == "deleting" { + return fmt.Errorf("already deleting") + } + return nil } func (r *NeptuneCluster) Remove(_ context.Context) error { + if r.settings.GetBool("DisableDeletionProtection") { + _, err := r.svc.ModifyDBCluster(&neptune.ModifyDBClusterInput{ + DBClusterIdentifier: r.ID, + DeletionProtection: ptr.Bool(false), + }) + if err != nil { + return err + } + } + _, err := r.svc.DeleteDBCluster(&neptune.DeleteDBClusterInput{ DBClusterIdentifier: r.ID, - SkipFinalSnapshot: aws.Bool(true), + SkipFinalSnapshot: ptr.Bool(true), }) return err diff --git a/resources/neptune-instance.go b/resources/neptune-instance.go index 0d846b60..e889e6c6 100644 --- a/resources/neptune-instance.go +++ b/resources/neptune-instance.go @@ -2,7 +2,8 @@ package resources import ( "context" - + "fmt" + "github.com/gotidy/ptr" "github.com/sirupsen/logrus" "github.com/aws/aws-sdk-go/aws" @@ -10,6 +11,7 @@ import ( "github.com/ekristen/libnuke/pkg/registry" "github.com/ekristen/libnuke/pkg/resource" + libsettings "github.com/ekristen/libnuke/pkg/settings" "github.com/ekristen/libnuke/pkg/types" "github.com/ekristen/aws-nuke/v3/pkg/nuke" @@ -23,6 +25,10 @@ func init() { Scope: nuke.Account, Resource: &NeptuneInstance{}, Lister: &NeptuneInstanceLister{}, + Settings: []string{ + "DisableClusterDeletionProtection", + "DisableDeletionProtection", + }, }) } @@ -63,10 +69,12 @@ func (l *NeptuneInstanceLister) List(_ context.Context, o interface{}) ([]resour } resources = append(resources, &NeptuneInstance{ - svc: svc, - ID: dbInstance.DBInstanceIdentifier, - Name: dbInstance.DBName, - Tags: dbTags, + svc: svc, + ID: dbInstance.DBInstanceIdentifier, + ClusterID: dbInstance.DBClusterIdentifier, + Name: dbInstance.DBName, + Status: dbInstance.DBInstanceStatus, + Tags: dbTags, }) } @@ -81,16 +89,50 @@ func (l *NeptuneInstanceLister) List(_ context.Context, o interface{}) ([]resour } type NeptuneInstance struct { - svc *neptune.Neptune - ID *string - Name *string - Tags []*neptune.Tag + svc *neptune.Neptune + settings *libsettings.Setting + ID *string + ClusterID *string + Name *string + Status *string + Tags []*neptune.Tag +} + +func (r *NeptuneInstance) Settings(settings *libsettings.Setting) { + r.settings = settings +} + +func (r *NeptuneInstance) Filter() error { + if ptr.ToString(r.Status) == "deleting" { + return fmt.Errorf("already deleting") + } + return nil } func (r *NeptuneInstance) Remove(_ context.Context) error { + if r.settings.GetBool("DisableClusterDeletionProtection") { + _, err := r.svc.ModifyDBCluster(&neptune.ModifyDBClusterInput{ + DBClusterIdentifier: r.ClusterID, + DeletionProtection: ptr.Bool(false), + }) + if err != nil { + return err + } + } + + if r.settings.GetBool("DisableDeletionProtection") { + _, err := r.svc.ModifyDBInstance(&neptune.ModifyDBInstanceInput{ + DBInstanceIdentifier: r.ID, + DeletionProtection: ptr.Bool(false), + }) + if err != nil { + return err + } + } + _, err := r.svc.DeleteDBInstance(&neptune.DeleteDBInstanceInput{ DBInstanceIdentifier: r.ID, - SkipFinalSnapshot: aws.Bool(true), + SkipFinalSnapshot: ptr.Bool(true), }) return err From ebb8d05837a337798a28bc0da834aa5110b214a5 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 18:03:29 -0700 Subject: [PATCH 09/10] docs(neptune): auto-generated, settings and properties --- docs/resources/neptune-cluster.md | 26 ++++++++++++++++++++++++++ docs/resources/neptune-instance.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/docs/resources/neptune-cluster.md b/docs/resources/neptune-cluster.md index f68c11ae..334f4bb1 100644 --- a/docs/resources/neptune-cluster.md +++ b/docs/resources/neptune-cluster.md @@ -15,6 +15,9 @@ NeptuneCluster - `ID`: No Description +- `Status`: No Description +- `tag::`: This resource has tags with property `Tags`. These are key/value pairs that are + added as their own property with the prefix of `tag:` (e.g. [tag:example: "value"]) !!! note - Using Properties Properties are what [Filters](../config-filtering.md) are written against in your configuration. You use the property @@ -28,3 +31,26 @@ the filter. The string value is always what is used in the output of the log format when a resource is identified. +## Settings + +- `DisableDeletionProtection` + + +### DisableDeletionProtection + +!!! note + There is currently no description for this setting. Often times settings are fairly self-explanatory. However, we + are working on adding descriptions for all settings. + +```text +DisableDeletionProtection +``` + +### DependsOn + +!!! important - Experimental Feature + This resource depends on a resource using the experimental feature. This means that the resource will + only be deleted if all the resources of a particular type are deleted first or reach a terminal state. + +- [NeptuneInstance](./neptune-instance.md) + diff --git a/docs/resources/neptune-instance.md b/docs/resources/neptune-instance.md index 89855d98..d8177a5b 100644 --- a/docs/resources/neptune-instance.md +++ b/docs/resources/neptune-instance.md @@ -14,8 +14,10 @@ NeptuneInstance ## Properties +- `ClusterID`: No Description - `ID`: No Description - `Name`: No Description +- `Status`: No Description - `tag::`: This resource has tags with property `Tags`. These are key/value pairs that are added as their own property with the prefix of `tag:` (e.g. [tag:example: "value"]) @@ -31,3 +33,30 @@ the filter. The string value is always what is used in the output of the log format when a resource is identified. +## Settings + +- `DisableClusterDeletionProtection` +- `DisableDeletionProtection` + + +### DisableClusterDeletionProtection + +!!! note + There is currently no description for this setting. Often times settings are fairly self-explanatory. However, we + are working on adding descriptions for all settings. + +```text +DisableClusterDeletionProtection +``` + + +### DisableDeletionProtection + +!!! note + There is currently no description for this setting. Often times settings are fairly self-explanatory. However, we + are working on adding descriptions for all settings. + +```text +DisableDeletionProtection +``` + From 462e441e14befbfdfaf07bcd9747aaef72d60725 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 12 Dec 2024 18:04:24 -0700 Subject: [PATCH 10/10] chore(golangci-lint): fix goimports --- resources/neptune-instance.go | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/neptune-instance.go b/resources/neptune-instance.go index e889e6c6..1e24100c 100644 --- a/resources/neptune-instance.go +++ b/resources/neptune-instance.go @@ -3,6 +3,7 @@ package resources import ( "context" "fmt" + "github.com/gotidy/ptr" "github.com/sirupsen/logrus"