From 50e7b594428714f14761590c04b7e86612d3580a Mon Sep 17 00:00:00 2001 From: Rob Watson Date: Fri, 12 Nov 2021 03:18:15 +0100 Subject: [PATCH] Add s3-delete-all command --- backend/cmd/s3-delete-all/main.go | 86 +++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 backend/cmd/s3-delete-all/main.go diff --git a/backend/cmd/s3-delete-all/main.go b/backend/cmd/s3-delete-all/main.go new file mode 100644 index 0000000..31104b3 --- /dev/null +++ b/backend/cmd/s3-delete-all/main.go @@ -0,0 +1,86 @@ +package main + +import ( + "context" + "errors" + "flag" + "log" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/smithy-go" +) + +const cmdName = "s3-delete-all" + +func main() { + var err error + ctx := context.Background() + + cfg, err := config.LoadDefaultConfig(ctx) + if err != nil { + log.Fatal(err) + } + s3Client := s3.NewFromConfig(cfg) + + var bucket string + flag.StringVar(&bucket, "bucket", "", "name of S3 bucket") + flag.Parse() + if bucket == "" { + log.Fatalf("usage: %s -bucket bucket", cmdName) + } + + // Delete S3 objects + + listObjectsInput := s3.ListObjectsV2Input{Bucket: aws.String(bucket), MaxKeys: 10_000} + listObjectsOutput, err := s3Client.ListObjectsV2(ctx, &listObjectsInput) + if err != nil { + log.Fatal(err) + } + + for _, object := range listObjectsOutput.Contents { + deleteObjectInput := s3.DeleteObjectInput{Bucket: aws.String(bucket), Key: object.Key} + _, err = s3Client.DeleteObject(ctx, &deleteObjectInput) + if err != nil { + log.Fatal(err) + } + + log.Printf("Deleted object %s", *object.Key) + } + + // Delete S3 uploads and parts + + listUploadsInput := s3.ListMultipartUploadsInput{Bucket: aws.String(bucket)} + listUploadsOutput, err := s3Client.ListMultipartUploads(ctx, &listUploadsInput) + if err != nil { + log.Fatal(err) + } + if listObjectsOutput.IsTruncated { + log.Fatal("TODO: handle IsTruncated") + } + + for _, upload := range listUploadsOutput.Uploads { + abortUploadInput := s3.AbortMultipartUploadInput{Bucket: aws.String(bucket), Key: upload.Key, UploadId: upload.UploadId} + _, err := s3Client.AbortMultipartUpload(ctx, &abortUploadInput) + if err != nil { + log.Fatal(err) + } + + listPartsInput := s3.ListPartsInput{Bucket: aws.String(bucket), Key: upload.Key, UploadId: upload.UploadId} + listPartsOutput, err := s3Client.ListParts(ctx, &listPartsInput) + if err != nil { + var ae smithy.APIError + if errors.As(err, &ae) && ae.ErrorCode() == "NoSuchUpload" { + log.Printf("Ignoring upload not found (id = %s)", *upload.UploadId) + continue + } + log.Fatal(err) + } + if len(listPartsOutput.Parts) > 0 { + log.Fatalf("some parts remain for key %s, upload %s (count = %d)", *upload.UploadId, *upload.Key, len(listPartsOutput.Parts)) + } + + log.Printf("Aborted upload %s", *upload.UploadId) + } +}