Search code examples
amazon-web-servicesgoamazon-s3aws-sdk-go

How to delete a non-empty S3 bucket using AWS SDK for Go v2


I'm using AWS sdk v2

and I need to delete a bucket that had objects

what's the best way to do so? is there something to force delete? or that deleted all the objects inside a bucket?


Solution

  • The AWS documentation Deleting a bucket describes how to delete a bucket that has objects. The documentation also provides an SDK example (written in Java, but mainly serves as a guideline) that performs the following steps:

    • Delete all objects
    • Delete all object versions (for versioned buckets)
    • Finally delete bucket

    There is no "force delete" option for non-empty buckets. You would need to implement the above steps.

    The following sample code shows how to completely delete a non-empty bucket:

    func main() {
        cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("us-east-1"))
        if err != nil {
            log.Fatalf("Failed to load config: %v", err)
        }
    
        bucket := aws.String("your-bucket-name")
        client := s3.NewFromConfig(cfg)
    
        deleteObject := func(bucket, key, versionId *string) {
            log.Printf("Object: %s/%s\n", *key, aws.ToString(versionId))
            _, err := client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{
                Bucket:    bucket,
                Key:       key,
                VersionId: versionId,
            })
            if err != nil {
                log.Fatalf("Failed to delete object: %v", err)
            }
        }
    
        in := &s3.ListObjectsV2Input{Bucket: bucket}
        for {
            out, err := client.ListObjectsV2(context.TODO(), in)
            if err != nil {
                log.Fatalf("Failed to list objects: %v", err)
            }
    
            for _, item := range out.Contents {
                deleteObject(bucket, item.Key, nil)
            }
    
            if out.IsTruncated {
                in.ContinuationToken = out.ContinuationToken
            } else {
                break
            }
        }
    
        inVer := &s3.ListObjectVersionsInput{Bucket: bucket}
        for {
            out, err := client.ListObjectVersions(context.TODO(), inVer)
            if err != nil {
                log.Fatalf("Failed to list version objects: %v", err)
            }
    
            for _, item := range out.DeleteMarkers {
                deleteObject(bucket, item.Key, item.VersionId)
            }
    
            for _, item := range out.Versions {
                deleteObject(bucket, item.Key, item.VersionId)
            }
    
            if out.IsTruncated {
                inVer.VersionIdMarker = out.NextVersionIdMarker
                inVer.KeyMarker = out.NextKeyMarker
            } else {
                break
            }
        }
    
        _, err = client.DeleteBucket(context.TODO(), &s3.DeleteBucketInput{Bucket: bucket})
        if err != nil {
            log.Fatalf("Failed to delete bucket: %v", err)
        }
    }
    

    You should probably optimize this further and use DeleteObjects for batch calls in order to reduce request overhead.