mirror of
https://github.com/openshift/installer.git
synced 2026-02-05 15:47:14 +01:00
** Migrate the use of resource tagging api to the sdk V2.
pkg/destroy/aws: ** Alter the function name from HandleErrorCode to handleErrorCode. The initial thought was that this function could be used in other areas of the code, but it will remain in destroy for now. pkg/destroy/aws/shared.go: ** Remove the session import and uses in the file.
This commit is contained in:
@@ -9,21 +9,24 @@ import (
|
||||
awsv2 "github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/aws/arn"
|
||||
configv2 "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
||||
ec2v2 "github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/aws/aws-sdk-go-v2/service/efs"
|
||||
elb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing"
|
||||
elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
|
||||
iamv2 "github.com/aws/aws-sdk-go-v2/service/iam"
|
||||
"github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi"
|
||||
tagtypes "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||
route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -34,6 +37,7 @@ import (
|
||||
awssession "github.com/openshift/installer/pkg/asset/installconfig/aws"
|
||||
"github.com/openshift/installer/pkg/destroy/providers"
|
||||
"github.com/openshift/installer/pkg/types"
|
||||
awstypes "github.com/openshift/installer/pkg/types/aws"
|
||||
"github.com/openshift/installer/pkg/version"
|
||||
)
|
||||
|
||||
@@ -67,6 +71,7 @@ type ClusterUninstaller struct {
|
||||
ClusterID string
|
||||
ClusterDomain string
|
||||
HostedZoneRole string
|
||||
endpoints []awstypes.ServiceEndpoint
|
||||
|
||||
// Session is the AWS session to be used for deletion. If nil, a
|
||||
// new session will be created based on the usual credential
|
||||
@@ -175,6 +180,7 @@ func New(logger logrus.FieldLogger, metadata *types.ClusterMetadata) (providers.
|
||||
ClusterDomain: metadata.AWS.ClusterDomain,
|
||||
Session: session,
|
||||
HostedZoneRole: metadata.AWS.HostedZoneRole,
|
||||
endpoints: metadata.AWS.ServiceEndpoints,
|
||||
EC2Client: ec2Client,
|
||||
IAMClient: iamClient,
|
||||
ELBClient: elbclient,
|
||||
@@ -198,6 +204,25 @@ func (o *ClusterUninstaller) Run() (*types.ClusterQuota, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func createResourceTaggingClientWithConfig(cfg awsv2.Config, region string, endpoints []awstypes.ServiceEndpoint) *resourcegroupstaggingapi.Client {
|
||||
return resourcegroupstaggingapi.NewFromConfig(cfg, func(options *resourcegroupstaggingapi.Options) {
|
||||
options.Region = region
|
||||
for _, endpoint := range endpoints {
|
||||
if strings.EqualFold(endpoint.Name, "resourcegroupstaggingapi") {
|
||||
options.BaseEndpoint = awsv2.String(endpoint.URL)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func createResourceTaggingClient(region string, endpoints []awstypes.ServiceEndpoint) (*resourcegroupstaggingapi.Client, error) {
|
||||
cfg, err := awssession.GetConfigWithOptions(context.Background(), configv2.WithRegion(region))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create AWS config for resource tagging client: %w", err)
|
||||
}
|
||||
return createResourceTaggingClientWithConfig(cfg, region, endpoints), nil
|
||||
}
|
||||
|
||||
// RunWithContext runs the uninstall process with a context.
|
||||
// The first return is the list of ARNs for resources that could not be destroyed.
|
||||
func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, error) {
|
||||
@@ -219,16 +244,31 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro
|
||||
Fn: request.MakeAddToUserAgentHandler("OpenShift/4.x Destroyer", version.Raw),
|
||||
})
|
||||
|
||||
tagClients := []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI{
|
||||
resourcegroupstaggingapi.New(awsSession),
|
||||
baseTaggingClient, err := createResourceTaggingClient(o.Region, o.endpoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tagClients := []*resourcegroupstaggingapi.Client{baseTaggingClient}
|
||||
|
||||
if o.HostedZoneRole != "" {
|
||||
cfg := awssession.GetR53ClientCfg(awsSession, o.HostedZoneRole)
|
||||
cfg, err := awssession.GetConfigWithOptions(ctx, configv2.WithRegion(endpointUSEast1))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create AWS config for resource tagging client: %w", err)
|
||||
}
|
||||
stsSvc, err := awssession.NewSTSClient(ctx, awssession.EndpointOptions{
|
||||
Region: endpointUSEast1,
|
||||
Endpoints: o.endpoints,
|
||||
}, sts.WithAPIOptions(middleware.AddUserAgentKeyValue("OpenShift/4.x Destroyer", version.Raw)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create STS client: %w", err)
|
||||
}
|
||||
|
||||
creds := stscreds.NewAssumeRoleProvider(stsSvc, o.HostedZoneRole)
|
||||
cfg.Credentials = awsv2.NewCredentialsCache(creds)
|
||||
// This client is specifically for finding route53 zones,
|
||||
// so it needs to use the global us-east-1 region.
|
||||
cfg.Region = aws.String(endpoints.UsEast1RegionID)
|
||||
tagClients = append(tagClients, resourcegroupstaggingapi.New(awsSession, cfg))
|
||||
|
||||
tagClients = append(tagClients, createResourceTaggingClientWithConfig(cfg, endpointUSEast1, o.endpoints))
|
||||
}
|
||||
|
||||
switch o.Region {
|
||||
@@ -238,13 +278,19 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro
|
||||
break
|
||||
case endpoints.UsGovEast1RegionID, endpoints.UsGovWest1RegionID:
|
||||
if o.Region != endpoints.UsGovWest1RegionID {
|
||||
tagClients = append(tagClients,
|
||||
resourcegroupstaggingapi.New(awsSession, aws.NewConfig().WithRegion(endpoints.UsGovWest1RegionID)))
|
||||
tagClient, err := createResourceTaggingClient(endpoints.UsGovWest1RegionID, o.endpoints)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create resource tagging client for usgov-west-1: %w", err)
|
||||
}
|
||||
tagClients = append(tagClients, tagClient)
|
||||
}
|
||||
default:
|
||||
if o.Region != endpoints.UsEast1RegionID {
|
||||
tagClients = append(tagClients,
|
||||
resourcegroupstaggingapi.New(awsSession, aws.NewConfig().WithRegion(endpoints.UsEast1RegionID)))
|
||||
tagClient, err := createResourceTaggingClientWithConfig(endpoints.UsEast1RegionID, o.endpoints)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create resource tagging client for default us-east-1: %w", err)
|
||||
}
|
||||
tagClients = append(tagClients, tagClient)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +321,7 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro
|
||||
// Terminate EC2 instances. The instances need to be terminated first so that we can ensure that there is nothing
|
||||
// running on the cluster creating new resources while we are attempting to delete resources, which could leak
|
||||
// the new resources.
|
||||
err = o.DeleteEC2Instances(ctx, awsSession, resourcesToDelete, deleted, tracker)
|
||||
err = o.DeleteEC2Instances(ctx, resourcesToDelete, deleted, tracker)
|
||||
if err != nil {
|
||||
return resourcesToDelete.UnsortedList(), err
|
||||
}
|
||||
@@ -284,7 +330,7 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro
|
||||
err = wait.PollImmediateUntil(
|
||||
time.Second*10,
|
||||
func() (done bool, err error) {
|
||||
newlyDeleted, loopError := o.DeleteResources(ctx, awsSession, resourcesToDelete.UnsortedList(), tracker)
|
||||
newlyDeleted, loopError := o.DeleteResources(ctx, resourcesToDelete.UnsortedList(), tracker)
|
||||
// Delete from the resources-to-delete set so that the current state of the resources to delete can be
|
||||
// returned if the context is completed.
|
||||
resourcesToDelete = resourcesToDelete.Difference(newlyDeleted)
|
||||
@@ -314,7 +360,7 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro
|
||||
return resourcesToDelete.UnsortedList(), err
|
||||
}
|
||||
|
||||
err = o.removeSharedTags(ctx, awsSession, tagClients, tracker)
|
||||
err = o.removeSharedTags(ctx, tagClients, tracker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -333,7 +379,7 @@ func (o *ClusterUninstaller) findUntaggableResources(ctx context.Context, delete
|
||||
profile := fmt.Sprintf("%s-%s-profile", o.ClusterID, profileType)
|
||||
response, err := o.IAMClient.GetInstanceProfile(ctx, &iamv2.GetInstanceProfileInput{InstanceProfileName: &profile})
|
||||
if err != nil {
|
||||
if strings.Contains(HandleErrorCode(err), "NoSuchEntity") {
|
||||
if strings.Contains(handleErrorCode(err), "NoSuchEntity") {
|
||||
continue
|
||||
}
|
||||
return resources, fmt.Errorf("failed to get IAM instance profile: %w", err)
|
||||
@@ -352,11 +398,11 @@ func (o *ClusterUninstaller) findUntaggableResources(ctx context.Context, delete
|
||||
// deleted - the resources that have already been deleted. Any resources specified in this set will be ignored.
|
||||
func (o *ClusterUninstaller) findResourcesToDelete(
|
||||
ctx context.Context,
|
||||
tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI,
|
||||
tagClients []*resourcegroupstaggingapi.Client,
|
||||
iamRoleSearch *IamRoleSearch,
|
||||
iamUserSearch *IamUserSearch,
|
||||
deleted sets.Set[string],
|
||||
) (sets.Set[string], []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, error) {
|
||||
) (sets.Set[string], []*resourcegroupstaggingapi.Client, error) {
|
||||
var errs []error
|
||||
resources, tagClients, err := FindTaggedResourcesToDelete(ctx, o.Logger, tagClients, o.Filters, iamRoleSearch, iamUserSearch, deleted)
|
||||
if err != nil {
|
||||
@@ -380,14 +426,14 @@ func (o *ClusterUninstaller) findResourcesToDelete(
|
||||
func FindTaggedResourcesToDelete(
|
||||
ctx context.Context,
|
||||
logger logrus.FieldLogger,
|
||||
tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI,
|
||||
tagClients []*resourcegroupstaggingapi.Client,
|
||||
filters []Filter,
|
||||
iamRoleSearch *IamRoleSearch,
|
||||
iamUserSearch *IamUserSearch,
|
||||
deleted sets.Set[string],
|
||||
) (sets.Set[string], []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, error) {
|
||||
) (sets.Set[string], []*resourcegroupstaggingapi.Client, error) {
|
||||
resources := sets.New[string]()
|
||||
var tagClientsWithResources []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI
|
||||
var tagClientsWithResources []*resourcegroupstaggingapi.Client
|
||||
var errs []error
|
||||
|
||||
// Find resources by tag
|
||||
@@ -402,7 +448,7 @@ func FindTaggedResourcesToDelete(
|
||||
if len(resourcesInTagClient) > 0 || err != nil {
|
||||
tagClientsWithResources = append(tagClientsWithResources, tagClient)
|
||||
} else {
|
||||
logger.Debugf("no deletions from %s, removing client", *tagClient.Config.Region)
|
||||
logger.Debugf("no deletions from %s, removing client", tagClient.Options().Region)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,39 +480,37 @@ func FindTaggedResourcesToDelete(
|
||||
func findResourcesByTag(
|
||||
ctx context.Context,
|
||||
logger logrus.FieldLogger,
|
||||
tagClient *resourcegroupstaggingapi.ResourceGroupsTaggingAPI,
|
||||
tagClient *resourcegroupstaggingapi.Client,
|
||||
filters []Filter,
|
||||
deleted sets.Set[string],
|
||||
) (sets.Set[string], error) {
|
||||
resources := sets.New[string]()
|
||||
for _, filter := range filters {
|
||||
logger.Debugf("search for matching resources by tag in %s matching %#+v", *tagClient.Config.Region, filter)
|
||||
tagFilters := make([]*resourcegroupstaggingapi.TagFilter, 0, len(filter))
|
||||
logger.Debugf("search for matching resources by tag in %s matching %#+v", tagClient.Options().Region, filter)
|
||||
tagFilters := make([]tagtypes.TagFilter, 0, len(filter))
|
||||
for key, value := range filter {
|
||||
tagFilters = append(tagFilters, &resourcegroupstaggingapi.TagFilter{
|
||||
tagFilters = append(tagFilters, tagtypes.TagFilter{
|
||||
Key: aws.String(key),
|
||||
Values: []*string{aws.String(value)},
|
||||
Values: []string{value},
|
||||
})
|
||||
}
|
||||
err := tagClient.GetResourcesPagesWithContext(
|
||||
ctx,
|
||||
&resourcegroupstaggingapi.GetResourcesInput{TagFilters: tagFilters},
|
||||
func(results *resourcegroupstaggingapi.GetResourcesOutput, lastPage bool) bool {
|
||||
for _, resource := range results.ResourceTagMappingList {
|
||||
arnString := *resource.ResourceARN
|
||||
if !deleted.Has(arnString) {
|
||||
resources.Insert(arnString)
|
||||
}
|
||||
|
||||
paginator := resourcegroupstaggingapi.NewGetResourcesPaginator(tagClient, &resourcegroupstaggingapi.GetResourcesInput{TagFilters: tagFilters})
|
||||
for paginator.HasMorePages() {
|
||||
page, err := paginator.NextPage(ctx)
|
||||
if err != nil {
|
||||
return resources, fmt.Errorf("failed to fetch resources by tag: %w", err)
|
||||
}
|
||||
|
||||
for _, resource := range page.ResourceTagMappingList {
|
||||
arnString := *resource.ResourceARN
|
||||
if !deleted.Has(arnString) {
|
||||
resources.Insert(arnString)
|
||||
}
|
||||
return !lastPage
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "get tagged resources")
|
||||
logger.Info(err)
|
||||
return resources, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
@@ -475,7 +519,7 @@ func findResourcesByTag(
|
||||
// resources - the resources to be deleted.
|
||||
//
|
||||
// The first return is the ARNs of the resources that were successfully deleted.
|
||||
func (o *ClusterUninstaller) DeleteResources(ctx context.Context, awsSession *session.Session, resources []string, tracker *ErrorTracker) (sets.Set[string], error) {
|
||||
func (o *ClusterUninstaller) DeleteResources(ctx context.Context, resources []string, tracker *ErrorTracker) (sets.Set[string], error) {
|
||||
deleted := sets.New[string]()
|
||||
for _, arnString := range resources {
|
||||
l := o.Logger.WithField("arn", arnString)
|
||||
@@ -638,7 +682,7 @@ func deleteRoute53(ctx context.Context, client *route53.Client, arn arn.ARN, log
|
||||
if err != nil {
|
||||
// In some cases AWS may return the zone in the list of tagged resources despite the fact
|
||||
// it no longer exists.
|
||||
if strings.Contains(HandleErrorCode(err), "NoSuchHostedZone") {
|
||||
if strings.Contains(handleErrorCode(err), "NoSuchHostedZone") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -850,7 +894,7 @@ func deleteFileSystem(ctx context.Context, client *efs.Client, fsid string, logg
|
||||
|
||||
_, err = client.DeleteFileSystem(ctx, &efs.DeleteFileSystemInput{FileSystemId: aws.String(fsid)})
|
||||
if err != nil {
|
||||
if strings.Contains(HandleErrorCode(err), "FileSystemNotFound") {
|
||||
if strings.Contains(handleErrorCode(err), "FileSystemNotFound") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -909,7 +953,7 @@ func deleteAccessPoint(ctx context.Context, client *efs.Client, id string, logge
|
||||
logger = logger.WithField("AccessPoint ID", id)
|
||||
_, err := client.DeleteAccessPoint(ctx, &efs.DeleteAccessPointInput{AccessPointId: aws.String(id)})
|
||||
if err != nil {
|
||||
if strings.Contains(HandleErrorCode(err), "AccessPointNotFound") {
|
||||
if strings.Contains(handleErrorCode(err), "AccessPointNotFound") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -923,7 +967,7 @@ func deleteMountTarget(ctx context.Context, client *efs.Client, id string, logge
|
||||
logger = logger.WithField("Mount Target ID", id)
|
||||
_, err := client.DeleteMountTarget(ctx, &efs.DeleteMountTargetInput{MountTargetId: aws.String(id)})
|
||||
if err != nil {
|
||||
if strings.Contains(HandleErrorCode(err), "MountTargetNotFound") {
|
||||
if strings.Contains(handleErrorCode(err), "MountTargetNotFound") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
elb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing"
|
||||
elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
|
||||
iamv2 "github.com/aws/aws-sdk-go-v2/service/iam"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
@@ -83,7 +82,7 @@ func findEC2Instances(ctx context.Context, ec2Client *ec2v2.Client, deleted sets
|
||||
}
|
||||
|
||||
// DeleteEC2Instances terminates all EC2 instances found.
|
||||
func (o *ClusterUninstaller) DeleteEC2Instances(ctx context.Context, awsSession *session.Session, toDelete sets.Set[string], deleted sets.Set[string], tracker *ErrorTracker) error {
|
||||
func (o *ClusterUninstaller) DeleteEC2Instances(ctx context.Context, toDelete sets.Set[string], deleted sets.Set[string], tracker *ErrorTracker) error {
|
||||
lastTerminateTime := time.Now()
|
||||
err := wait.PollUntilContextCancel(
|
||||
ctx,
|
||||
@@ -103,7 +102,7 @@ func (o *ClusterUninstaller) DeleteEC2Instances(ctx context.Context, awsSession
|
||||
instancesToDelete = instancesNotTerminated
|
||||
lastTerminateTime = time.Now()
|
||||
}
|
||||
newlyDeleted, err := o.DeleteResources(ctx, awsSession, instancesToDelete, tracker)
|
||||
newlyDeleted, err := o.DeleteResources(ctx, instancesToDelete, tracker)
|
||||
// Delete from the resources-to-delete set so that the current state of the resources to delete can be
|
||||
// returned if the context is completed.
|
||||
toDelete = toDelete.Difference(newlyDeleted)
|
||||
@@ -173,7 +172,7 @@ func deleteEC2DHCPOptions(ctx context.Context, client *ec2v2.Client, id string,
|
||||
DhcpOptionsId: &id,
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidDhcpOptions.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidDhcpOptions.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -190,7 +189,7 @@ func deleteEC2Image(ctx context.Context, client *ec2v2.Client, id string, logger
|
||||
ImageIds: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidAMI.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidAMI.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -217,7 +216,7 @@ func deleteEC2Image(ctx context.Context, client *ec2v2.Client, id string, logger
|
||||
ImageId: &id,
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidAMI.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidAMI.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -232,7 +231,7 @@ func deleteEC2ElasticIP(ctx context.Context, client *ec2v2.Client, id string, lo
|
||||
AllocationId: aws.String(id),
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidAllocation.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidAllocation.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -247,7 +246,7 @@ func terminateEC2Instance(ctx context.Context, ec2Client *ec2v2.Client, iamClien
|
||||
InstanceIds: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidInstance.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidInstance.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -301,7 +300,7 @@ func deleteEC2InternetGateway(ctx context.Context, client *ec2v2.Client, id stri
|
||||
})
|
||||
if err == nil {
|
||||
logger.WithField("vpc", *vpc.VpcId).Debug("Detached")
|
||||
} else if HandleErrorCode(err) == "Gateway.NotAttached" {
|
||||
} else if handleErrorCode(err) == "Gateway.NotAttached" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -323,7 +322,7 @@ func deleteEC2CarrierGateway(ctx context.Context, client *ec2v2.Client, id strin
|
||||
CarrierGatewayId: &id,
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidCarrierGateway.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidCarrierGateway.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -338,7 +337,7 @@ func deleteEC2NATGateway(ctx context.Context, client *ec2v2.Client, id string, l
|
||||
NatGatewayId: aws.String(id),
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "NatGateway.NotFound" {
|
||||
if handleErrorCode(err) == "NatGateway.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -391,7 +390,7 @@ func deleteEC2PlacementGroup(ctx context.Context, client *ec2v2.Client, id strin
|
||||
GroupIds: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidPlacementGroup.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidPlacementGroup.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -414,7 +413,7 @@ func deleteEC2RouteTable(ctx context.Context, client *ec2v2.Client, id string, l
|
||||
RouteTableIds: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidRouteTableID.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidRouteTableID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -544,7 +543,7 @@ func deleteEC2SecurityGroup(ctx context.Context, client *ec2v2.Client, id string
|
||||
GroupIds: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidGroup.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidGroup.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -594,7 +593,7 @@ func deleteEC2SecurityGroupObject(ctx context.Context, client *ec2v2.Client, gro
|
||||
GroupId: group.GroupId,
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidGroup.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidGroup.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -648,7 +647,7 @@ func deleteEC2Snapshot(ctx context.Context, client *ec2v2.Client, id string, log
|
||||
SnapshotId: &id,
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidSnapshot.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidSnapshot.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -663,7 +662,7 @@ func deleteEC2NetworkInterface(ctx context.Context, client *ec2v2.Client, id str
|
||||
NetworkInterfaceId: aws.String(id),
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidNetworkInterfaceID.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidNetworkInterfaceID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -714,7 +713,7 @@ func deleteEC2Subnet(ctx context.Context, client *ec2v2.Client, id string, logge
|
||||
SubnetId: aws.String(id),
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidSubnetID.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidSubnetID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -766,7 +765,7 @@ func deleteEC2Volume(ctx context.Context, client *ec2v2.Client, id string, logge
|
||||
VolumeId: aws.String(id),
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidVolume.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidVolume.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -845,7 +844,7 @@ func deleteEC2VPCEndpointsByVPC(ctx context.Context, client *ec2v2.Client, vpc s
|
||||
for _, endpoint := range response.VpcEndpoints {
|
||||
err := deleteEC2VPCEndpoint(ctx, client, *endpoint.VpcEndpointId, logger.WithField("VPC endpoint", *endpoint.VpcEndpointId))
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidVpcID.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidVpcID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -860,7 +859,7 @@ func deleteEC2VPCPeeringConnection(ctx context.Context, client *ec2v2.Client, id
|
||||
VpcPeeringConnectionId: &id,
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidVpcPeeringConnection.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidVpcPeeringConnection.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(err, "cannot delete VPC Peering Connection %s", id)
|
||||
@@ -907,7 +906,7 @@ func deleteEC2VPCEndpointService(ctx context.Context, client *ec2v2.Client, id s
|
||||
ServiceIds: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
if HandleErrorCode(err) == "InvalidVpcEndpointService.NotFound" {
|
||||
if handleErrorCode(err) == "InvalidVpcEndpointService.NotFound" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(err, "cannot delete VPC Endpoint Service %s", id)
|
||||
|
||||
@@ -111,7 +111,7 @@ func deleteElasticLoadBalancerListener(ctx context.Context, client *elbapiv2.Cli
|
||||
ListenerArn: aws.String(arn.String()),
|
||||
})
|
||||
if err != nil {
|
||||
if strings.Contains(HandleErrorCode(err), "ListenerNotFound") {
|
||||
if strings.Contains(handleErrorCode(err), "ListenerNotFound") {
|
||||
logger.Info("Not found or already deleted")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// HandleErrorCode takes the error and extracts the error code if it was successfully cast as an API Error.
|
||||
func HandleErrorCode(err error) string {
|
||||
// handleErrorCode takes the error and extracts the error code if it was successfully cast as an API Error.
|
||||
func handleErrorCode(err error) string {
|
||||
var apiErr smithy.APIError
|
||||
if errors.As(err, &apiErr) {
|
||||
return apiErr.ErrorCode()
|
||||
|
||||
@@ -46,7 +46,7 @@ func (search *IamRoleSearch) find(ctx context.Context) (arns []string, names []s
|
||||
response, err := search.Client.ListRoleTags(ctx, &iamv2.ListRoleTagsInput{RoleName: role.RoleName})
|
||||
if err != nil {
|
||||
switch {
|
||||
case strings.Contains(HandleErrorCode(err), "NoSuchEntity"):
|
||||
case strings.Contains(handleErrorCode(err), "NoSuchEntity"):
|
||||
// The role does not exist.
|
||||
// Ignore this IAM Role and donot report this error via
|
||||
// lastError
|
||||
@@ -195,7 +195,7 @@ func deleteIAMInstanceProfileByName(ctx context.Context, client *iamv2.Client, n
|
||||
InstanceProfileName: name,
|
||||
})
|
||||
if err != nil {
|
||||
if strings.Contains(HandleErrorCode(err), "NoSuchEntity") {
|
||||
if strings.Contains(handleErrorCode(err), "NoSuchEntity") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -218,7 +218,7 @@ func deleteIAMInstanceProfile(ctx context.Context, client *iamv2.Client, profile
|
||||
InstanceProfileName: &name,
|
||||
})
|
||||
if err != nil {
|
||||
if strings.Contains(HandleErrorCode(err), "NoSuchEntity") {
|
||||
if strings.Contains(handleErrorCode(err), "NoSuchEntity") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -6,15 +6,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/aws/arn"
|
||||
"github.com/aws/aws-sdk-go-v2/service/iam"
|
||||
"github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi"
|
||||
tagtypes "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||
route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
//"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
@@ -22,12 +20,11 @@ import (
|
||||
|
||||
func (o *ClusterUninstaller) removeSharedTags(
|
||||
ctx context.Context,
|
||||
session *session.Session,
|
||||
tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI,
|
||||
tagClients []*resourcegroupstaggingapi.Client,
|
||||
tracker *ErrorTracker,
|
||||
) error {
|
||||
for _, key := range o.clusterOwnedKeys() {
|
||||
if err := o.removeSharedTag(ctx, session, tagClients, key, tracker); err != nil {
|
||||
if err := o.removeSharedTag(ctx, tagClients, key, tracker); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -50,64 +47,67 @@ func (o *ClusterUninstaller) clusterOwnedKeys() []string {
|
||||
return keys
|
||||
}
|
||||
|
||||
func (o *ClusterUninstaller) removeSharedTag(ctx context.Context, session *session.Session, tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, key string, tracker *ErrorTracker) error {
|
||||
func (o *ClusterUninstaller) removeSharedTag(ctx context.Context, tagClients []*resourcegroupstaggingapi.Client, key string, tracker *ErrorTracker) error {
|
||||
const sharedValue = "shared"
|
||||
|
||||
request := &resourcegroupstaggingapi.UntagResourcesInput{
|
||||
TagKeys: []*string{aws.String(key)},
|
||||
TagKeys: []string{key},
|
||||
}
|
||||
|
||||
removed := map[string]struct{}{}
|
||||
tagClients = append([]*resourcegroupstaggingapi.ResourceGroupsTaggingAPI(nil), tagClients...)
|
||||
tagClients = append([]*resourcegroupstaggingapi.Client(nil), tagClients...)
|
||||
for len(tagClients) > 0 {
|
||||
nextTagClients := tagClients[:0]
|
||||
for _, tagClient := range tagClients {
|
||||
o.Logger.Debugf("Search for and remove tags in %s matching %s: shared", *tagClient.Config.Region, key)
|
||||
var lastErr error
|
||||
o.Logger.Debugf("Search for and remove tags in %s matching %s: shared", tagClient.Options().Region, key)
|
||||
var arns []string
|
||||
err := tagClient.GetResourcesPagesWithContext(
|
||||
ctx,
|
||||
&resourcegroupstaggingapi.GetResourcesInput{TagFilters: []*resourcegroupstaggingapi.TagFilter{{
|
||||
paginator := resourcegroupstaggingapi.NewGetResourcesPaginator(tagClient, &resourcegroupstaggingapi.GetResourcesInput{
|
||||
TagFilters: []tagtypes.TagFilter{{
|
||||
Key: aws.String(key),
|
||||
Values: []*string{aws.String(sharedValue)},
|
||||
}}},
|
||||
func(results *resourcegroupstaggingapi.GetResourcesOutput, lastPage bool) bool {
|
||||
for _, resource := range results.ResourceTagMappingList {
|
||||
arnString := aws.StringValue(resource.ResourceARN)
|
||||
logger := o.Logger.WithField("arn", arnString)
|
||||
parsedARN, err := arn.Parse(arnString)
|
||||
if err != nil {
|
||||
logger.WithError(err).Debug("could not parse ARN")
|
||||
continue
|
||||
}
|
||||
if _, ok := removed[arnString]; !ok {
|
||||
if err := o.cleanSharedARN(ctx, parsedARN, logger); err != nil {
|
||||
tracker.suppressWarning(arnString, err, logger)
|
||||
if err := ctx.Err(); err != nil {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
arns = append(arns, arnString)
|
||||
}
|
||||
}
|
||||
Values: []string{sharedValue},
|
||||
}}})
|
||||
for paginator.HasMorePages() {
|
||||
page, err := paginator.NextPage(ctx)
|
||||
if err != nil {
|
||||
o.Logger.Debugf("failed to get resources: %v", err)
|
||||
lastErr = err
|
||||
break
|
||||
}
|
||||
|
||||
return !lastPage
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
err2 := errors.Wrap(err, "get tagged resources")
|
||||
o.Logger.Info(err2)
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case resourcegroupstaggingapi.ErrorCodeInvalidParameterException:
|
||||
for _, resource := range page.ResourceTagMappingList {
|
||||
arnString := *resource.ResourceARN
|
||||
logger := o.Logger.WithField("arn", arnString)
|
||||
parsedARN, err := arn.Parse(arnString)
|
||||
if err != nil {
|
||||
logger.WithError(err).Debug("could not parse ARN")
|
||||
continue
|
||||
}
|
||||
if _, ok := removed[arnString]; !ok {
|
||||
if err := o.cleanSharedARN(ctx, parsedARN, logger); err != nil {
|
||||
tracker.suppressWarning(arnString, err, logger)
|
||||
if err := ctx.Err(); err != nil {
|
||||
lastErr = fmt.Errorf("failed to remove tag %q: %w", key, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
arns = append(arns, arnString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if lastErr != nil {
|
||||
o.Logger.Infof("failed to get tagged resources: %v", lastErr)
|
||||
var invalidParameter tagtypes.InvalidParameterException
|
||||
if errors.As(lastErr, &invalidParameter) {
|
||||
continue
|
||||
}
|
||||
nextTagClients = append(nextTagClients, tagClient)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(arns) == 0 {
|
||||
o.Logger.Debugf("No matches in %s for %s: shared, removing client", *tagClient.Config.Region, key)
|
||||
o.Logger.Debugf("No matches in %s for %s: shared, removing client", o.Region, key)
|
||||
continue
|
||||
}
|
||||
// appending the tag client here but it needs to be removed if there is a InvalidParameterException when trying to
|
||||
@@ -115,15 +115,13 @@ func (o *ClusterUninstaller) removeSharedTag(ctx context.Context, session *sessi
|
||||
nextTagClients = append(nextTagClients, tagClient)
|
||||
|
||||
for i := 0; i < len(arns); i += 20 {
|
||||
request.ResourceARNList = make([]*string, 0, 20)
|
||||
request.ResourceARNList = make([]string, 0, 20)
|
||||
for j := 0; i+j < len(arns) && j < 20; j++ {
|
||||
request.ResourceARNList = append(request.ResourceARNList, aws.String(arns[i+j]))
|
||||
request.ResourceARNList = append(request.ResourceARNList, arns[i+j])
|
||||
}
|
||||
result, err := tagClient.UntagResourcesWithContext(ctx, request)
|
||||
result, err := tagClient.UntagResources(ctx, request)
|
||||
if err != nil {
|
||||
var awsErr awserr.Error
|
||||
ok := errors.As(err, &awsErr)
|
||||
if ok && awsErr.Code() == resourcegroupstaggingapi.ErrorCodeInvalidParameterException {
|
||||
if strings.Contains(handleErrorCode(err), "InvalidParameter") {
|
||||
nextTagClients = nextTagClients[:len(nextTagClients)-1]
|
||||
}
|
||||
err = errors.Wrap(err, "untag shared resources")
|
||||
@@ -131,19 +129,18 @@ func (o *ClusterUninstaller) removeSharedTag(ctx context.Context, session *sessi
|
||||
continue
|
||||
}
|
||||
for _, arn := range request.ResourceARNList {
|
||||
if info, failed := result.FailedResourcesMap[*arn]; failed {
|
||||
o.Logger.WithField("arn", *arn).Infof("Failed to remove tag %s: shared; error=%s", key, *info.ErrorMessage)
|
||||
if info, failed := result.FailedResourcesMap[arn]; failed {
|
||||
o.Logger.WithField("arn", arn).Infof("Failed to remove tag %s: shared; error=%s", key, *info.ErrorMessage)
|
||||
continue
|
||||
}
|
||||
o.Logger.WithField("arn", *arn).Infof("Removed tag %s: shared", key)
|
||||
removed[*arn] = exists
|
||||
o.Logger.WithField("arn", arn).Infof("Removed tag %s: shared", key)
|
||||
removed[arn] = exists
|
||||
}
|
||||
}
|
||||
}
|
||||
tagClients = nextTagClients
|
||||
}
|
||||
|
||||
iamClient := iam.New(session)
|
||||
iamRoleSearch := &IamRoleSearch{
|
||||
Client: o.IAMClient,
|
||||
Filters: []Filter{{key: sharedValue}},
|
||||
@@ -163,9 +160,9 @@ func (o *ClusterUninstaller) removeSharedTag(ctx context.Context, session *sessi
|
||||
o.Logger.Debugf("Removing the shared tag from the %q IAM role", role)
|
||||
input := &iam.UntagRoleInput{
|
||||
RoleName: &role,
|
||||
TagKeys: []*string{&key},
|
||||
TagKeys: []string{key},
|
||||
}
|
||||
if _, err := iamClient.UntagRoleWithContext(ctx, input); err != nil {
|
||||
if _, err := o.IAMClient.UntagRole(ctx, input); err != nil {
|
||||
done = false
|
||||
o.Logger.Infof("Could not remove the shared tag from the %q IAM role: %v", role, err)
|
||||
}
|
||||
@@ -228,14 +225,14 @@ func (o *ClusterUninstaller) cleanSharedHostedZone(ctx context.Context, id strin
|
||||
|
||||
for _, recordSet := range page.ResourceRecordSets {
|
||||
// skip record sets that are not part of the cluster
|
||||
name := aws.StringValue(recordSet.Name)
|
||||
name := *recordSet.Name
|
||||
if !strings.HasSuffix(name, dottedClusterDomain) {
|
||||
continue
|
||||
}
|
||||
if len(name) == len(dottedClusterDomain) {
|
||||
continue
|
||||
}
|
||||
recordsetFields := logrus.Fields{"recordset": fmt.Sprintf("%s (%s)", aws.StringValue(recordSet.Name), recordSet.Type)}
|
||||
recordsetFields := logrus.Fields{"recordset": fmt.Sprintf("%s (%s)", *recordSet.Name, recordSet.Type)}
|
||||
// delete any matching record sets in the public hosted zone
|
||||
if publicZoneID != "" {
|
||||
publicZoneLogger := logger.WithField("id", publicZoneID)
|
||||
@@ -283,8 +280,7 @@ func deleteMatchingRecordSetInPublicZone(ctx context.Context, client *route53.Cl
|
||||
return nil
|
||||
}
|
||||
matchingRecordSet := out.ResourceRecordSets[0]
|
||||
if aws.StringValue(matchingRecordSet.Name) != aws.StringValue(recordSet.Name) ||
|
||||
matchingRecordSet.Type != recordSet.Type {
|
||||
if *matchingRecordSet.Name != *recordSet.Name || matchingRecordSet.Type != recordSet.Type {
|
||||
return nil
|
||||
}
|
||||
return deleteRoute53RecordSet(ctx, client, zoneID, &matchingRecordSet, logger)
|
||||
|
||||
Reference in New Issue
Block a user