diff --git a/aws/resources/tgw_peering_attachment.go b/aws/resources/tgw_peering_attachment.go new file mode 100644 index 00000000..e15323e7 --- /dev/null +++ b/aws/resources/tgw_peering_attachment.go @@ -0,0 +1,53 @@ +package resources + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/gruntwork-io/cloud-nuke/logging" + "github.com/gruntwork-io/cloud-nuke/report" + "github.com/gruntwork-io/go-commons/errors" +) + +func (tgpa *TransitGatewayPeeringAttachment) getAll(c context.Context, configObj config.Config) ([]*string, error) { + var ids []*string + err := tgpa.Client.DescribeTransitGatewayPeeringAttachmentsPagesWithContext(tgpa.Context, &ec2.DescribeTransitGatewayPeeringAttachmentsInput{}, func(result *ec2.DescribeTransitGatewayPeeringAttachmentsOutput, lastPage bool) bool { + for _, attachment := range result.TransitGatewayPeeringAttachments { + if configObj.TransitGatewayPeeringAttachment.ShouldInclude(config.ResourceValue{ + Time: attachment.CreationTime, + }) { + ids = append(ids, attachment.TransitGatewayAttachmentId) + } + } + + return !lastPage + }) + if err != nil { + return nil, errors.WithStackTrace(err) + } + + return ids, nil +} + +func (tgpa *TransitGatewayPeeringAttachment) nukeAll(ids []*string) error { + for _, id := range ids { + _, err := tgpa.Client.DeleteTransitGatewayPeeringAttachmentWithContext(tgpa.Context, &ec2.DeleteTransitGatewayPeeringAttachmentInput{ + TransitGatewayAttachmentId: id, + }) + // Record status of this resource + report.Record(report.Entry{ + Identifier: aws.StringValue(id), + ResourceType: tgpa.ResourceName(), + Error: err, + }) + if err != nil { + logging.Errorf("[Failed] %s", err) + } else { + logging.Debugf("Deleted Transit Gateway Peering Attachment: %s", *id) + } + } + + return nil +} diff --git a/aws/resources/tgw_peering_attachment_test.go b/aws/resources/tgw_peering_attachment_test.go new file mode 100644 index 00000000..edb8882f --- /dev/null +++ b/aws/resources/tgw_peering_attachment_test.go @@ -0,0 +1,95 @@ +package resources + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + awsgo "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/stretchr/testify/require" +) + +type mockedTransitGatewayPeeringAttachment struct { + ec2iface.EC2API + DescribeTransitGatewayPeeringAttachmentsOutput ec2.DescribeTransitGatewayPeeringAttachmentsOutput + DeleteTransitGatewayPeeringAttachmentOutput ec2.DeleteTransitGatewayPeeringAttachmentOutput +} + +func (m mockedTransitGatewayPeeringAttachment) DescribeTransitGatewayPeeringAttachmentsPagesWithContext(_ awsgo.Context, _ *ec2.DescribeTransitGatewayPeeringAttachmentsInput, fn func(*ec2.DescribeTransitGatewayPeeringAttachmentsOutput, bool) bool, _ ...request.Option) error { + fn(&m.DescribeTransitGatewayPeeringAttachmentsOutput, true) + return nil +} + +func (m mockedTransitGatewayPeeringAttachment) DeleteTransitGatewayPeeringAttachmentWithContext(_ awsgo.Context, _ *ec2.DeleteTransitGatewayPeeringAttachmentInput, _ ...request.Option) (*ec2.DeleteTransitGatewayPeeringAttachmentOutput, error) { + return &m.DeleteTransitGatewayPeeringAttachmentOutput, nil +} + +func TestTransitGatewayPeeringAttachment_getAll(t *testing.T) { + + t.Parallel() + + now := time.Now() + attachment1 := "attachement1" + attachment2 := "attachement2" + tgpa := TransitGatewayPeeringAttachment{ + Client: mockedTransitGatewayPeeringAttachment{ + DescribeTransitGatewayPeeringAttachmentsOutput: ec2.DescribeTransitGatewayPeeringAttachmentsOutput{ + TransitGatewayPeeringAttachments: []*ec2.TransitGatewayPeeringAttachment{ + { + TransitGatewayAttachmentId: aws.String(attachment1), + CreationTime: aws.Time(now), + }, + { + TransitGatewayAttachmentId: aws.String(attachment2), + CreationTime: aws.Time(now.Add(1)), + }, + }, + }, + }, + } + + tests := map[string]struct { + configObj config.ResourceType + expected []string + }{ + "emptyFilter": { + configObj: config.ResourceType{}, + expected: []string{attachment1, attachment2}, + }, + "timeAfterExclusionFilter": { + configObj: config.ResourceType{ + ExcludeRule: config.FilterRule{ + TimeAfter: aws.Time(now), + }}, + expected: []string{attachment1}, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + names, err := tgpa.getAll(context.Background(), config.Config{ + TransitGatewayPeeringAttachment: tc.configObj, + }) + require.NoError(t, err) + require.Equal(t, tc.expected, aws.StringValueSlice(names)) + }) + } +} + +func TestTransitGatewayPeeringAttachment_nukeAll(t *testing.T) { + + t.Parallel() + + tgw := TransitGatewayPeeringAttachment{ + Client: mockedTransitGatewayPeeringAttachment{ + DeleteTransitGatewayPeeringAttachmentOutput: ec2.DeleteTransitGatewayPeeringAttachmentOutput{}, + }, + } + + err := tgw.nukeAll([]*string{aws.String("test-attachment")}) + require.NoError(t, err) +} diff --git a/aws/resources/tgw_peering_attachment_types.go b/aws/resources/tgw_peering_attachment_types.go new file mode 100644 index 00000000..d9dfae78 --- /dev/null +++ b/aws/resources/tgw_peering_attachment_types.go @@ -0,0 +1,58 @@ +package resources + +import ( + "context" + + awsgo "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/gruntwork-io/go-commons/errors" +) + +// TransitGatewayPeeringAttachment - represents all transit gateways peering attachment +type TransitGatewayPeeringAttachment struct { + BaseAwsResource + Client ec2iface.EC2API + Region string + Ids []string +} + +func (tgpa *TransitGatewayPeeringAttachment) Init(session *session.Session) { + tgpa.Client = ec2.New(session) +} + +func (tgpa *TransitGatewayPeeringAttachment) ResourceName() string { + return "transit-gateway-peering-attachment" +} + +func (tgpa *TransitGatewayPeeringAttachment) MaxBatchSize() int { + return maxBatchSize +} + +func (tgpa *TransitGatewayPeeringAttachment) ResourceIdentifiers() []string { + return tgpa.Ids +} + +func (tgpa *TransitGatewayPeeringAttachment) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { + return configObj.TransitGateway +} + +func (tgpa *TransitGatewayPeeringAttachment) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { + identifiers, err := tgpa.getAll(c, configObj) + if err != nil { + return nil, err + } + + tgpa.Ids = awsgo.StringValueSlice(identifiers) + return tgpa.Ids, nil +} + +func (tgpa *TransitGatewayPeeringAttachment) Nuke(identifiers []string) error { + if err := tgpa.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + return errors.WithStackTrace(err) + } + + return nil +} diff --git a/aws/resources/tgw_route_tables.go b/aws/resources/tgw_route_tables.go new file mode 100644 index 00000000..63a5d2ef --- /dev/null +++ b/aws/resources/tgw_route_tables.go @@ -0,0 +1,70 @@ +package resources + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + awsgo "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/gruntwork-io/cloud-nuke/logging" + "github.com/gruntwork-io/go-commons/errors" +) + +// Returns a formatted string of TransitGatewayRouteTable IDs +func (tgw *TransitGatewaysRouteTables) getAll(c context.Context, configObj config.Config) ([]*string, error) { + // Remove default route table, that will be deleted along with its TransitGateway + param := &ec2.DescribeTransitGatewayRouteTablesInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("default-association-route-table"), + Values: []*string{ + aws.String("false"), + }, + }, + }, + } + + result, err := tgw.Client.DescribeTransitGatewayRouteTablesWithContext(tgw.Context, param) + if err != nil { + return nil, errors.WithStackTrace(err) + } + + var ids []*string + for _, transitGatewayRouteTable := range result.TransitGatewayRouteTables { + if configObj.TransitGatewayRouteTable.ShouldInclude(config.ResourceValue{Time: transitGatewayRouteTable.CreationTime}) && + awsgo.StringValue(transitGatewayRouteTable.State) != "deleted" && awsgo.StringValue(transitGatewayRouteTable.State) != "deleting" { + ids = append(ids, transitGatewayRouteTable.TransitGatewayRouteTableId) + } + } + + return ids, nil +} + +// Delete all TransitGatewayRouteTables +func (tgw *TransitGatewaysRouteTables) nukeAll(ids []*string) error { + if len(ids) == 0 { + logging.Debugf("No Transit Gateway Route Tables to nuke in region %s", tgw.Region) + return nil + } + + logging.Debugf("Deleting all Transit Gateway Route Tables in region %s", tgw.Region) + var deletedIds []*string + + for _, id := range ids { + param := &ec2.DeleteTransitGatewayRouteTableInput{ + TransitGatewayRouteTableId: id, + } + + _, err := tgw.Client.DeleteTransitGatewayRouteTableWithContext(tgw.Context, param) + if err != nil { + logging.Debugf("[Failed] %s", err) + } else { + deletedIds = append(deletedIds, id) + logging.Debugf("Deleted Transit Gateway Route Table: %s", *id) + } + } + + logging.Debugf("[OK] %d Transit Gateway Route Table(s) deleted in %s", len(deletedIds), tgw.Region) + return nil +} diff --git a/aws/resources/tgw_route_tables_test.go b/aws/resources/tgw_route_tables_test.go new file mode 100644 index 00000000..81f86f09 --- /dev/null +++ b/aws/resources/tgw_route_tables_test.go @@ -0,0 +1,94 @@ +package resources + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + awsgo "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/stretchr/testify/require" +) + +type mockedTransitGatewayRouteTable struct { + ec2iface.EC2API + DescribeTransitGatewayRouteTablesOutput ec2.DescribeTransitGatewayRouteTablesOutput + DeleteTransitGatewayRouteTableOutput ec2.DeleteTransitGatewayRouteTableOutput +} + +func (m mockedTransitGatewayRouteTable) DescribeTransitGatewayRouteTablesWithContext(_ awsgo.Context, _ *ec2.DescribeTransitGatewayRouteTablesInput, _ ...request.Option) (*ec2.DescribeTransitGatewayRouteTablesOutput, error) { + return &m.DescribeTransitGatewayRouteTablesOutput, nil +} + +func (m mockedTransitGatewayRouteTable) DeleteTransitGatewayRouteTableWithContext(_ awsgo.Context, _ *ec2.DeleteTransitGatewayRouteTableInput, _ ...request.Option) (*ec2.DeleteTransitGatewayRouteTableOutput, error) { + return &m.DeleteTransitGatewayRouteTableOutput, nil +} +func TestTransitGatewayRouteTables_GetAll(t *testing.T) { + + t.Parallel() + + now := time.Now() + tableId1 := "table1" + tableId2 := "table2" + tgw := TransitGatewaysRouteTables{ + Client: mockedTransitGatewayRouteTable{ + DescribeTransitGatewayRouteTablesOutput: ec2.DescribeTransitGatewayRouteTablesOutput{ + TransitGatewayRouteTables: []*ec2.TransitGatewayRouteTable{ + { + TransitGatewayRouteTableId: aws.String(tableId1), + CreationTime: aws.Time(now), + State: aws.String("available"), + }, + { + TransitGatewayRouteTableId: aws.String(tableId2), + CreationTime: aws.Time(now.Add(1)), + State: aws.String("deleting"), + }, + }, + }, + }, + } + tests := map[string]struct { + configObj config.ResourceType + expected []string + }{ + "emptyFilter": { + configObj: config.ResourceType{}, + expected: []string{tableId1}, + }, + "timeAfterExclusionFilter": { + configObj: config.ResourceType{ + ExcludeRule: config.FilterRule{ + TimeAfter: aws.Time(now.Add(-1 * time.Hour)), + }}, + expected: []string{}, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + names, err := tgw.getAll(context.Background(), config.Config{ + TransitGatewayRouteTable: tc.configObj, + }) + require.NoError(t, err) + require.Equal(t, tc.expected, aws.StringValueSlice(names)) + }) + } +} + +func TestTransitGatewayRouteTables_NukeAll(t *testing.T) { + + t.Parallel() + + tgw := TransitGatewaysRouteTables{ + Client: mockedTransitGatewayRouteTable{ + DeleteTransitGatewayRouteTableOutput: ec2.DeleteTransitGatewayRouteTableOutput{}, + }, + } + + err := tgw.nukeAll([]*string{aws.String("test-route-table")}) + require.NoError(t, err) +} diff --git a/aws/resources/tgw_route_tables_types.go b/aws/resources/tgw_route_tables_types.go new file mode 100644 index 00000000..5da3055a --- /dev/null +++ b/aws/resources/tgw_route_tables_types.go @@ -0,0 +1,58 @@ +package resources + +import ( + "context" + + awsgo "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/gruntwork-io/go-commons/errors" +) + +// TransitGatewaysRouteTables - represents all transit gateways route tables +type TransitGatewaysRouteTables struct { + BaseAwsResource + Client ec2iface.EC2API + Region string + Ids []string +} + +func (tgw *TransitGatewaysRouteTables) Init(session *session.Session) { + tgw.Client = ec2.New(session) +} + +// ResourceName - the simple name of the aws resource +func (tgw *TransitGatewaysRouteTables) ResourceName() string { + return "transit-gateway-route-table" +} + +// MaxBatchSize - Tentative batch size to ensure AWS doesn't throttle +func (tgw *TransitGatewaysRouteTables) MaxBatchSize() int { + return maxBatchSize +} + +// ResourceIdentifiers - The arns of the transit gateways route tables +func (tgw *TransitGatewaysRouteTables) ResourceIdentifiers() []string { + return tgw.Ids +} + +func (tgw *TransitGatewaysRouteTables) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { + identifiers, err := tgw.getAll(c, configObj) + if err != nil { + return nil, err + } + + tgw.Ids = awsgo.StringValueSlice(identifiers) + return tgw.Ids, nil +} + +// Nuke - nuke 'em all!!! +func (tgw *TransitGatewaysRouteTables) Nuke(identifiers []string) error { + if err := tgw.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + return errors.WithStackTrace(err) + } + + return nil +} diff --git a/aws/resources/tgw_vpc_attachment.go b/aws/resources/tgw_vpc_attachment.go new file mode 100644 index 00000000..293d4a73 --- /dev/null +++ b/aws/resources/tgw_vpc_attachment.go @@ -0,0 +1,99 @@ +package resources + +import ( + "context" + "time" + + "github.com/aws/aws-sdk-go/aws" + awsgo "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + goerror "github.com/go-errors/errors" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/gruntwork-io/cloud-nuke/logging" + "github.com/gruntwork-io/cloud-nuke/report" + "github.com/gruntwork-io/go-commons/errors" +) + +// Returns a formated string of TransitGatewayVpcAttachment IDs +func (tgw *TransitGatewaysVpcAttachment) getAll(c context.Context, configObj config.Config) ([]*string, error) { + result, err := tgw.Client.DescribeTransitGatewayVpcAttachmentsWithContext(tgw.Context, &ec2.DescribeTransitGatewayVpcAttachmentsInput{}) + if err != nil { + return nil, errors.WithStackTrace(err) + } + + var ids []*string + for _, tgwVpcAttachment := range result.TransitGatewayVpcAttachments { + if configObj.TransitGatewaysVpcAttachment.ShouldInclude(config.ResourceValue{Time: tgwVpcAttachment.CreationTime}) && + awsgo.StringValue(tgwVpcAttachment.State) != "deleted" && awsgo.StringValue(tgwVpcAttachment.State) != "deleting" { + ids = append(ids, tgwVpcAttachment.TransitGatewayAttachmentId) + } + } + + return ids, nil +} + +// Delete all TransitGatewayVpcAttachments +func (tgw *TransitGatewaysVpcAttachment) nukeAll(ids []*string) error { + if len(ids) == 0 { + logging.Debugf("No Transit Gateway Vpc Attachments to nuke in region %s", tgw.Region) + return nil + } + + logging.Debugf("Deleting all Transit Gateway Vpc Attachments in region %s", tgw.Region) + var deletedIds []*string + + for _, id := range ids { + param := &ec2.DeleteTransitGatewayVpcAttachmentInput{ + TransitGatewayAttachmentId: id, + } + + _, err := tgw.Client.DeleteTransitGatewayVpcAttachmentWithContext(tgw.Context, param) + + // Record status of this resource + e := report.Entry{ + Identifier: aws.StringValue(id), + ResourceType: "Transit Gateway", + Error: err, + } + report.Record(e) + + if err != nil { + logging.Debugf("[Failed] %s", err) + } else { + deletedIds = append(deletedIds, id) + logging.Debugf("Deleted Transit Gateway Vpc Attachment: %s", *id) + } + } + + if waiterr := waitForTransitGatewayAttachementToBeDeleted(*tgw); waiterr != nil { + return errors.WithStackTrace(waiterr) + } + logging.Debugf("[OK] %d Transit Gateway Vpc Attachment(s) deleted in %s", len(deletedIds), tgw.Region) + return nil +} + +func waitForTransitGatewayAttachementToBeDeleted(tgw TransitGatewaysVpcAttachment) error { + for i := 0; i < 30; i++ { + gateways, err := tgw.Client.DescribeTransitGatewayVpcAttachments( + &ec2.DescribeTransitGatewayVpcAttachmentsInput{ + TransitGatewayAttachmentIds: aws.StringSlice(tgw.Ids), + Filters: []*ec2.Filter{ + { + Name: awsgo.String("state"), + Values: []*string{awsgo.String("deleting")}, + }, + }, + }, + ) + if err != nil { + return err + } + if len(gateways.TransitGatewayVpcAttachments) == 0 { + return nil + } + logging.Info("Waiting for transit gateways attachemensts to be deleted...") + time.Sleep(10 * time.Second) + } + + return goerror.New("timed out waiting for transit gateway attahcments to be successfully deleted") +} diff --git a/aws/resources/tgw_vpc_attachment_test.go b/aws/resources/tgw_vpc_attachment_test.go new file mode 100644 index 00000000..3e04c679 --- /dev/null +++ b/aws/resources/tgw_vpc_attachment_test.go @@ -0,0 +1,98 @@ +package resources + +import ( + "context" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + awsgo "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/stretchr/testify/require" +) + +type mockedTransitGatewayVpcAttachment struct { + ec2iface.EC2API + DescribeTransitGatewayVpcAttachmentsOutput ec2.DescribeTransitGatewayVpcAttachmentsOutput + DeleteTransitGatewayVpcAttachmentOutput ec2.DeleteTransitGatewayVpcAttachmentOutput +} + +func (m mockedTransitGatewayVpcAttachment) DescribeTransitGatewayVpcAttachmentsWithContext(_ awsgo.Context, _ *ec2.DescribeTransitGatewayVpcAttachmentsInput, _ ...request.Option) (*ec2.DescribeTransitGatewayVpcAttachmentsOutput, error) { + return &m.DescribeTransitGatewayVpcAttachmentsOutput, nil +} +func (m mockedTransitGatewayVpcAttachment) DescribeTransitGatewayVpcAttachments(_ *ec2.DescribeTransitGatewayVpcAttachmentsInput) (*ec2.DescribeTransitGatewayVpcAttachmentsOutput, error) { + return &m.DescribeTransitGatewayVpcAttachmentsOutput, nil +} + +func (m mockedTransitGatewayVpcAttachment) DeleteTransitGatewayVpcAttachmentWithContext(_ awsgo.Context, _ *ec2.DeleteTransitGatewayVpcAttachmentInput, _ ...request.Option) (*ec2.DeleteTransitGatewayVpcAttachmentOutput, error) { + return &m.DeleteTransitGatewayVpcAttachmentOutput, nil +} + +func TestTransitGatewayVpcAttachments_GetAll(t *testing.T) { + + t.Parallel() + + now := time.Now() + attachment1 := "attachement1" + attachment2 := "attachement2" + tgw := TransitGatewaysVpcAttachment{ + Client: mockedTransitGatewayVpcAttachment{ + DescribeTransitGatewayVpcAttachmentsOutput: ec2.DescribeTransitGatewayVpcAttachmentsOutput{ + TransitGatewayVpcAttachments: []*ec2.TransitGatewayVpcAttachment{ + { + TransitGatewayAttachmentId: aws.String(attachment1), + CreationTime: aws.Time(now), + State: aws.String("available"), + }, + { + TransitGatewayAttachmentId: aws.String(attachment2), + CreationTime: aws.Time(now.Add(1)), + State: aws.String("deleting"), + }, + }, + }, + }, + } + tests := map[string]struct { + configObj config.ResourceType + expected []string + }{ + "emptyFilter": { + configObj: config.ResourceType{}, + expected: []string{attachment1}, + }, + "timeAfterExclusionFilter": { + configObj: config.ResourceType{ + ExcludeRule: config.FilterRule{ + TimeAfter: aws.Time(now.Add(-1 * time.Hour)), + }}, + expected: []string{}, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + names, err := tgw.getAll(context.Background(), config.Config{ + TransitGatewaysVpcAttachment: tc.configObj, + }) + require.NoError(t, err) + require.Equal(t, tc.expected, aws.StringValueSlice(names)) + }) + } +} + +func TestTransitGatewayVpcAttachments_NukeAll(t *testing.T) { + + t.Parallel() + + tgw := TransitGatewaysVpcAttachment{ + Client: mockedTransitGatewayVpcAttachment{ + DeleteTransitGatewayVpcAttachmentOutput: ec2.DeleteTransitGatewayVpcAttachmentOutput{}, + }, + } + + err := tgw.nukeAll([]*string{aws.String("test-attachment")}) + require.NoError(t, err) +} diff --git a/aws/resources/tgw_vpc_attachment_types.go b/aws/resources/tgw_vpc_attachment_types.go new file mode 100644 index 00000000..0a59971a --- /dev/null +++ b/aws/resources/tgw_vpc_attachment_types.go @@ -0,0 +1,58 @@ +package resources + +import ( + "context" + + awsgo "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/gruntwork-io/cloud-nuke/config" + "github.com/gruntwork-io/go-commons/errors" +) + +// TransitGatewaysVpcAttachment - represents all transit gateways vpc attachments +type TransitGatewaysVpcAttachment struct { + BaseAwsResource + Client ec2iface.EC2API + Region string + Ids []string +} + +func (tgw *TransitGatewaysVpcAttachment) Init(session *session.Session) { + tgw.Client = ec2.New(session) +} + +// ResourceName - the simple name of the aws resource +func (tgw *TransitGatewaysVpcAttachment) ResourceName() string { + return "transit-gateway-attachment" +} + +// MaxBatchSize - Tentative batch size to ensure AWS doesn't throttle +func (tgw *TransitGatewaysVpcAttachment) MaxBatchSize() int { + return maxBatchSize +} + +// ResourceIdentifiers - The Ids of the transit gateways +func (tgw *TransitGatewaysVpcAttachment) ResourceIdentifiers() []string { + return tgw.Ids +} + +func (tgw *TransitGatewaysVpcAttachment) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { + identifiers, err := tgw.getAll(c, configObj) + if err != nil { + return nil, err + } + + tgw.Ids = awsgo.StringValueSlice(identifiers) + return tgw.Ids, nil +} + +// Nuke - nuke 'em all!!! +func (tgw *TransitGatewaysVpcAttachment) Nuke(identifiers []string) error { + if err := tgw.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + return errors.WithStackTrace(err) + } + + return nil +} diff --git a/aws/resources/transit_gateway.go b/aws/resources/transit_gateway.go index f93152b9..cd17f8c4 100644 --- a/aws/resources/transit_gateway.go +++ b/aws/resources/transit_gateway.go @@ -2,12 +2,10 @@ package resources import ( "context" - "time" "github.com/aws/aws-sdk-go/aws" awsgo "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - goerror "github.com/go-errors/errors" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" @@ -104,186 +102,3 @@ func (tgw *TransitGateways) nukeAll(ids []*string) error { logging.Debugf("[OK] %d Transit Gateway(s) deleted in %s", len(deletedIds), tgw.Region) return nil } - -// Returns a formatted string of TranstGatewayRouteTable IDs -func (tgw *TransitGatewaysRouteTables) getAll(c context.Context, configObj config.Config) ([]*string, error) { - // Remove defalt route table, that will be deleted along with its TransitGateway - param := &ec2.DescribeTransitGatewayRouteTablesInput{ - Filters: []*ec2.Filter{ - { - Name: aws.String("default-association-route-table"), - Values: []*string{ - aws.String("false"), - }, - }, - }, - } - - result, err := tgw.Client.DescribeTransitGatewayRouteTablesWithContext(tgw.Context, param) - if err != nil { - return nil, errors.WithStackTrace(err) - } - - var ids []*string - for _, transitGatewayRouteTable := range result.TransitGatewayRouteTables { - if configObj.TransitGatewayRouteTable.ShouldInclude(config.ResourceValue{Time: transitGatewayRouteTable.CreationTime}) && - awsgo.StringValue(transitGatewayRouteTable.State) != "deleted" && awsgo.StringValue(transitGatewayRouteTable.State) != "deleting" { - ids = append(ids, transitGatewayRouteTable.TransitGatewayRouteTableId) - } - } - - return ids, nil -} - -// Delete all TransitGatewayRouteTables -func (tgw *TransitGatewaysRouteTables) nukeAll(ids []*string) error { - if len(ids) == 0 { - logging.Debugf("No Transit Gateway Route Tables to nuke in region %s", tgw.Region) - return nil - } - - logging.Debugf("Deleting all Transit Gateway Route Tables in region %s", tgw.Region) - var deletedIds []*string - - for _, id := range ids { - param := &ec2.DeleteTransitGatewayRouteTableInput{ - TransitGatewayRouteTableId: id, - } - - _, err := tgw.Client.DeleteTransitGatewayRouteTableWithContext(tgw.Context, param) - if err != nil { - logging.Debugf("[Failed] %s", err) - } else { - deletedIds = append(deletedIds, id) - logging.Debugf("Deleted Transit Gateway Route Table: %s", *id) - } - } - - logging.Debugf("[OK] %d Transit Gateway Route Table(s) deleted in %s", len(deletedIds), tgw.Region) - return nil -} - -// Returns a formated string of TransitGatewayVpcAttachment IDs -func (tgw *TransitGatewaysVpcAttachment) getAll(c context.Context, configObj config.Config) ([]*string, error) { - result, err := tgw.Client.DescribeTransitGatewayVpcAttachmentsWithContext(tgw.Context, &ec2.DescribeTransitGatewayVpcAttachmentsInput{}) - if err != nil { - return nil, errors.WithStackTrace(err) - } - - var ids []*string - for _, tgwVpcAttachment := range result.TransitGatewayVpcAttachments { - if configObj.TransitGatewaysVpcAttachment.ShouldInclude(config.ResourceValue{Time: tgwVpcAttachment.CreationTime}) && - awsgo.StringValue(tgwVpcAttachment.State) != "deleted" && awsgo.StringValue(tgwVpcAttachment.State) != "deleting" { - ids = append(ids, tgwVpcAttachment.TransitGatewayAttachmentId) - } - } - - return ids, nil -} - -// Delete all TransitGatewayVpcAttachments -func (tgw *TransitGatewaysVpcAttachment) nukeAll(ids []*string) error { - if len(ids) == 0 { - logging.Debugf("No Transit Gateway Vpc Attachments to nuke in region %s", tgw.Region) - return nil - } - - logging.Debugf("Deleting all Transit Gateway Vpc Attachments in region %s", tgw.Region) - var deletedIds []*string - - for _, id := range ids { - param := &ec2.DeleteTransitGatewayVpcAttachmentInput{ - TransitGatewayAttachmentId: id, - } - - _, err := tgw.Client.DeleteTransitGatewayVpcAttachmentWithContext(tgw.Context, param) - - // Record status of this resource - e := report.Entry{ - Identifier: aws.StringValue(id), - ResourceType: "Transit Gateway", - Error: err, - } - report.Record(e) - - if err != nil { - logging.Debugf("[Failed] %s", err) - } else { - deletedIds = append(deletedIds, id) - logging.Debugf("Deleted Transit Gateway Vpc Attachment: %s", *id) - } - } - - if waiterr := waitForTransitGatewayAttachementToBeDeleted(*tgw); waiterr != nil { - return errors.WithStackTrace(waiterr) - } - logging.Debugf(("[OK] %d Transit Gateway Vpc Attachment(s) deleted in %s"), len(deletedIds), tgw.Region) - return nil -} - -func (tgpa *TransitGatewayPeeringAttachment) getAll(c context.Context, configObj config.Config) ([]*string, error) { - var ids []*string - err := tgpa.Client.DescribeTransitGatewayPeeringAttachmentsPagesWithContext(tgpa.Context, &ec2.DescribeTransitGatewayPeeringAttachmentsInput{}, func(result *ec2.DescribeTransitGatewayPeeringAttachmentsOutput, lastPage bool) bool { - for _, attachment := range result.TransitGatewayPeeringAttachments { - if configObj.TransitGatewayPeeringAttachment.ShouldInclude(config.ResourceValue{ - Time: attachment.CreationTime, - }) { - ids = append(ids, attachment.TransitGatewayAttachmentId) - } - } - - return !lastPage - }) - if err != nil { - return nil, errors.WithStackTrace(err) - } - - return ids, nil -} - -func (tgpa *TransitGatewayPeeringAttachment) nukeAll(ids []*string) error { - for _, id := range ids { - _, err := tgpa.Client.DeleteTransitGatewayPeeringAttachmentWithContext(tgpa.Context, &ec2.DeleteTransitGatewayPeeringAttachmentInput{ - TransitGatewayAttachmentId: id, - }) - // Record status of this resource - report.Record(report.Entry{ - Identifier: aws.StringValue(id), - ResourceType: tgpa.ResourceName(), - Error: err, - }) - if err != nil { - logging.Errorf("[Failed] %s", err) - } else { - logging.Debugf("Deleted Transit Gateway Peering Attachment: %s", *id) - } - } - - return nil -} - -func waitForTransitGatewayAttachementToBeDeleted(tgw TransitGatewaysVpcAttachment) error { - for i := 0; i < 30; i++ { - gateways, err := tgw.Client.DescribeTransitGatewayVpcAttachments( - &ec2.DescribeTransitGatewayVpcAttachmentsInput{ - TransitGatewayAttachmentIds: aws.StringSlice(tgw.Ids), - Filters: []*ec2.Filter{ - { - Name: awsgo.String("state"), - Values: []*string{awsgo.String("deleting")}, - }, - }, - }, - ) - if err != nil { - return err - } - if len(gateways.TransitGatewayVpcAttachments) == 0 { - return nil - } - logging.Info("Waiting for transit gateways attachemensts to be deleted...") - time.Sleep(10 * time.Second) - } - - return goerror.New("timed out waiting for transit gateway attahcments to be successfully deleted") -} diff --git a/aws/resources/transit_gateway_test.go b/aws/resources/transit_gateway_test.go index ba4039d3..ef376a46 100644 --- a/aws/resources/transit_gateway_test.go +++ b/aws/resources/transit_gateway_test.go @@ -20,33 +20,6 @@ type mockedTransitGateway struct { DeleteTransitGatewayOutput ec2.DeleteTransitGatewayOutput } -type mockedTransitGatewayRouteTable struct { - ec2iface.EC2API - DescribeTransitGatewayRouteTablesOutput ec2.DescribeTransitGatewayRouteTablesOutput - DeleteTransitGatewayRouteTableOutput ec2.DeleteTransitGatewayRouteTableOutput -} - -type mockedTransitGatewayVpcAttachment struct { - ec2iface.EC2API - DescribeTransitGatewayVpcAttachmentsOutput ec2.DescribeTransitGatewayVpcAttachmentsOutput - DeleteTransitGatewayVpcAttachmentOutput ec2.DeleteTransitGatewayVpcAttachmentOutput -} - -type mockedTransitGatewayPeeringAttachment struct { - ec2iface.EC2API - DescribeTransitGatewayPeeringAttachmentsOutput ec2.DescribeTransitGatewayPeeringAttachmentsOutput - DeleteTransitGatewayPeeringAttachmentOutput ec2.DeleteTransitGatewayPeeringAttachmentOutput -} - -func (m mockedTransitGatewayPeeringAttachment) DescribeTransitGatewayPeeringAttachmentsPagesWithContext(_ awsgo.Context, _ *ec2.DescribeTransitGatewayPeeringAttachmentsInput, fn func(*ec2.DescribeTransitGatewayPeeringAttachmentsOutput, bool) bool, _ ...request.Option) error { - fn(&m.DescribeTransitGatewayPeeringAttachmentsOutput, true) - return nil -} - -func (m mockedTransitGatewayPeeringAttachment) DeleteTransitGatewayPeeringAttachmentWithContext(_ awsgo.Context, _ *ec2.DeleteTransitGatewayPeeringAttachmentInput, _ ...request.Option) (*ec2.DeleteTransitGatewayPeeringAttachmentOutput, error) { - return &m.DeleteTransitGatewayPeeringAttachmentOutput, nil -} - func (m mockedTransitGateway) DescribeTransitGatewaysWithContext(_ awsgo.Context, _ *ec2.DescribeTransitGatewaysInput, _ ...request.Option) (*ec2.DescribeTransitGatewaysOutput, error) { return &m.DescribeTransitGatewaysOutput, nil } @@ -55,25 +28,6 @@ func (m mockedTransitGateway) DeleteTransitGatewayWithContext(_ awsgo.Context, _ return &m.DeleteTransitGatewayOutput, nil } -func (m mockedTransitGatewayRouteTable) DescribeTransitGatewayRouteTablesWithContext(_ awsgo.Context, _ *ec2.DescribeTransitGatewayRouteTablesInput, _ ...request.Option) (*ec2.DescribeTransitGatewayRouteTablesOutput, error) { - return &m.DescribeTransitGatewayRouteTablesOutput, nil -} - -func (m mockedTransitGatewayRouteTable) DeleteTransitGatewayRouteTableWithContext(_ awsgo.Context, _ *ec2.DeleteTransitGatewayRouteTableInput, _ ...request.Option) (*ec2.DeleteTransitGatewayRouteTableOutput, error) { - return &m.DeleteTransitGatewayRouteTableOutput, nil -} - -func (m mockedTransitGatewayVpcAttachment) DescribeTransitGatewayVpcAttachmentsWithContext(_ awsgo.Context, _ *ec2.DescribeTransitGatewayVpcAttachmentsInput, _ ...request.Option) (*ec2.DescribeTransitGatewayVpcAttachmentsOutput, error) { - return &m.DescribeTransitGatewayVpcAttachmentsOutput, nil -} -func (m mockedTransitGatewayVpcAttachment) DescribeTransitGatewayVpcAttachments(_ *ec2.DescribeTransitGatewayVpcAttachmentsInput) (*ec2.DescribeTransitGatewayVpcAttachmentsOutput, error) { - return &m.DescribeTransitGatewayVpcAttachmentsOutput, nil -} - -func (m mockedTransitGatewayVpcAttachment) DeleteTransitGatewayVpcAttachmentWithContext(_ awsgo.Context, _ *ec2.DeleteTransitGatewayVpcAttachmentInput, _ ...request.Option) (*ec2.DeleteTransitGatewayVpcAttachmentOutput, error) { - return &m.DeleteTransitGatewayVpcAttachmentOutput, nil -} - func TestTransitGateways_GetAll(t *testing.T) { t.Parallel() @@ -142,200 +96,3 @@ func TestTransitGateways_NukeAll(t *testing.T) { err := tgw.nukeAll([]*string{aws.String("test-gateway")}) require.NoError(t, err) } - -func TestTransitGatewayRouteTables_GetAll(t *testing.T) { - - t.Parallel() - - now := time.Now() - tableId1 := "table1" - tableId2 := "table2" - tgw := TransitGatewaysRouteTables{ - Client: mockedTransitGatewayRouteTable{ - DescribeTransitGatewayRouteTablesOutput: ec2.DescribeTransitGatewayRouteTablesOutput{ - TransitGatewayRouteTables: []*ec2.TransitGatewayRouteTable{ - { - TransitGatewayRouteTableId: aws.String(tableId1), - CreationTime: aws.Time(now), - State: aws.String("available"), - }, - { - TransitGatewayRouteTableId: aws.String(tableId2), - CreationTime: aws.Time(now.Add(1)), - State: aws.String("deleting"), - }, - }, - }, - }, - } - tests := map[string]struct { - configObj config.ResourceType - expected []string - }{ - "emptyFilter": { - configObj: config.ResourceType{}, - expected: []string{tableId1}, - }, - "timeAfterExclusionFilter": { - configObj: config.ResourceType{ - ExcludeRule: config.FilterRule{ - TimeAfter: aws.Time(now.Add(-1 * time.Hour)), - }}, - expected: []string{}, - }, - } - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - names, err := tgw.getAll(context.Background(), config.Config{ - TransitGatewayRouteTable: tc.configObj, - }) - require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) - }) - } -} - -func TestTransitGatewayRouteTables_NukeAll(t *testing.T) { - - t.Parallel() - - tgw := TransitGatewaysRouteTables{ - Client: mockedTransitGatewayRouteTable{ - DeleteTransitGatewayRouteTableOutput: ec2.DeleteTransitGatewayRouteTableOutput{}, - }, - } - - err := tgw.nukeAll([]*string{aws.String("test-route-table")}) - require.NoError(t, err) -} - -func TestTransitGatewayVpcAttachments_GetAll(t *testing.T) { - - t.Parallel() - - now := time.Now() - attachment1 := "attachement1" - attachment2 := "attachement2" - tgw := TransitGatewaysVpcAttachment{ - Client: mockedTransitGatewayVpcAttachment{ - DescribeTransitGatewayVpcAttachmentsOutput: ec2.DescribeTransitGatewayVpcAttachmentsOutput{ - TransitGatewayVpcAttachments: []*ec2.TransitGatewayVpcAttachment{ - { - TransitGatewayAttachmentId: aws.String(attachment1), - CreationTime: aws.Time(now), - State: aws.String("available"), - }, - { - TransitGatewayAttachmentId: aws.String(attachment2), - CreationTime: aws.Time(now.Add(1)), - State: aws.String("deleting"), - }, - }, - }, - }, - } - tests := map[string]struct { - configObj config.ResourceType - expected []string - }{ - "emptyFilter": { - configObj: config.ResourceType{}, - expected: []string{attachment1}, - }, - "timeAfterExclusionFilter": { - configObj: config.ResourceType{ - ExcludeRule: config.FilterRule{ - TimeAfter: aws.Time(now.Add(-1 * time.Hour)), - }}, - expected: []string{}, - }, - } - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - names, err := tgw.getAll(context.Background(), config.Config{ - TransitGatewaysVpcAttachment: tc.configObj, - }) - require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) - }) - } -} - -func TestTransitGatewayVpcAttachments_NukeAll(t *testing.T) { - - t.Parallel() - - tgw := TransitGatewaysVpcAttachment{ - Client: mockedTransitGatewayVpcAttachment{ - DeleteTransitGatewayVpcAttachmentOutput: ec2.DeleteTransitGatewayVpcAttachmentOutput{}, - }, - } - - err := tgw.nukeAll([]*string{aws.String("test-attachment")}) - require.NoError(t, err) -} - -func TestTransitGatewayPeeringAttachment_getAll(t *testing.T) { - - t.Parallel() - - now := time.Now() - attachment1 := "attachement1" - attachment2 := "attachement2" - tgpa := TransitGatewayPeeringAttachment{ - Client: mockedTransitGatewayPeeringAttachment{ - DescribeTransitGatewayPeeringAttachmentsOutput: ec2.DescribeTransitGatewayPeeringAttachmentsOutput{ - TransitGatewayPeeringAttachments: []*ec2.TransitGatewayPeeringAttachment{ - { - TransitGatewayAttachmentId: aws.String(attachment1), - CreationTime: aws.Time(now), - }, - { - TransitGatewayAttachmentId: aws.String(attachment2), - CreationTime: aws.Time(now.Add(1)), - }, - }, - }, - }, - } - - tests := map[string]struct { - configObj config.ResourceType - expected []string - }{ - "emptyFilter": { - configObj: config.ResourceType{}, - expected: []string{attachment1, attachment2}, - }, - "timeAfterExclusionFilter": { - configObj: config.ResourceType{ - ExcludeRule: config.FilterRule{ - TimeAfter: aws.Time(now), - }}, - expected: []string{attachment1}, - }, - } - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - names, err := tgpa.getAll(context.Background(), config.Config{ - TransitGatewayPeeringAttachment: tc.configObj, - }) - require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) - }) - } -} - -func TestTransitGatewayPeeringAttachment_nukeAll(t *testing.T) { - - t.Parallel() - - tgw := TransitGatewayPeeringAttachment{ - Client: mockedTransitGatewayPeeringAttachment{ - DeleteTransitGatewayPeeringAttachmentOutput: ec2.DeleteTransitGatewayPeeringAttachmentOutput{}, - }, - } - - err := tgw.nukeAll([]*string{aws.String("test-attachment")}) - require.NoError(t, err) -} diff --git a/aws/resources/transit_gateway_types.go b/aws/resources/transit_gateway_types.go index 6ef50d95..ad3656ef 100644 --- a/aws/resources/transit_gateway_types.go +++ b/aws/resources/transit_gateway_types.go @@ -11,144 +11,6 @@ import ( "github.com/gruntwork-io/go-commons/errors" ) -// TransitGateways - represents all transit gateways -type TransitGatewayPeeringAttachment struct { - BaseAwsResource - Client ec2iface.EC2API - Region string - Ids []string -} - -func (tgpa *TransitGatewayPeeringAttachment) Init(session *session.Session) { - tgpa.Client = ec2.New(session) -} - -func (tgpa *TransitGatewayPeeringAttachment) ResourceName() string { - return "transit-gateway-peering-attachment" -} - -func (tgpa *TransitGatewayPeeringAttachment) MaxBatchSize() int { - return maxBatchSize -} - -func (tgpa *TransitGatewayPeeringAttachment) ResourceIdentifiers() []string { - return tgpa.Ids -} - -func (tgpa *TransitGatewayPeeringAttachment) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { - return configObj.TransitGateway -} - -func (tgpa *TransitGatewayPeeringAttachment) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { - identifiers, err := tgpa.getAll(c, configObj) - if err != nil { - return nil, err - } - - tgpa.Ids = awsgo.StringValueSlice(identifiers) - return tgpa.Ids, nil -} - -func (tgpa *TransitGatewayPeeringAttachment) Nuke(identifiers []string) error { - if err := tgpa.nukeAll(awsgo.StringSlice(identifiers)); err != nil { - return errors.WithStackTrace(err) - } - - return nil -} - -// TransitGatewaysVpcAttachment - represents all transit gateways vpc attachments -type TransitGatewaysVpcAttachment struct { - BaseAwsResource - Client ec2iface.EC2API - Region string - Ids []string -} - -func (tgw *TransitGatewaysVpcAttachment) Init(session *session.Session) { - tgw.Client = ec2.New(session) -} - -// ResourceName - the simple name of the aws resource -func (tgw *TransitGatewaysVpcAttachment) ResourceName() string { - return "transit-gateway-attachment" -} - -// MaxBatchSize - Tentative batch size to ensure AWS doesn't throttle -func (tgw *TransitGatewaysVpcAttachment) MaxBatchSize() int { - return maxBatchSize -} - -// ResourceIdentifiers - The Ids of the transit gateways -func (tgw *TransitGatewaysVpcAttachment) ResourceIdentifiers() []string { - return tgw.Ids -} - -func (tgw *TransitGatewaysVpcAttachment) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { - identifiers, err := tgw.getAll(c, configObj) - if err != nil { - return nil, err - } - - tgw.Ids = awsgo.StringValueSlice(identifiers) - return tgw.Ids, nil -} - -// Nuke - nuke 'em all!!! -func (tgw *TransitGatewaysVpcAttachment) Nuke(identifiers []string) error { - if err := tgw.nukeAll(awsgo.StringSlice(identifiers)); err != nil { - return errors.WithStackTrace(err) - } - - return nil -} - -// TransitGatewaysRouteTables - represents all transit gateways route tables -type TransitGatewaysRouteTables struct { - BaseAwsResource - Client ec2iface.EC2API - Region string - Ids []string -} - -func (tgw *TransitGatewaysRouteTables) Init(session *session.Session) { - tgw.Client = ec2.New(session) -} - -// ResourceName - the simple name of the aws resource -func (tgw *TransitGatewaysRouteTables) ResourceName() string { - return "transit-gateway-route-table" -} - -// MaxBatchSize - Tentative batch size to ensure AWS doesn't throttle -func (tgw *TransitGatewaysRouteTables) MaxBatchSize() int { - return maxBatchSize -} - -// ResourceIdentifiers - The arns of the transit gateways route tables -func (tgw *TransitGatewaysRouteTables) ResourceIdentifiers() []string { - return tgw.Ids -} - -func (tgw *TransitGatewaysRouteTables) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { - identifiers, err := tgw.getAll(c, configObj) - if err != nil { - return nil, err - } - - tgw.Ids = awsgo.StringValueSlice(identifiers) - return tgw.Ids, nil -} - -// Nuke - nuke 'em all!!! -func (tgw *TransitGatewaysRouteTables) Nuke(identifiers []string) error { - if err := tgw.nukeAll(awsgo.StringSlice(identifiers)); err != nil { - return errors.WithStackTrace(err) - } - - return nil -} - // TransitGateways - represents all transit gateways type TransitGateways struct { BaseAwsResource