猿问

如何强制删除 S3 存储桶中的所有对象版本,然后最终使用 aws-sdk-go 删除整个存储桶?

我有一个启用了版本控制的 S3 存储桶。存储桶几乎没有具有版本的文件。我编写了一个示例 golang 程序,它可以执行以下操作:

  • GetBucketVersioning - 它能够获取存储桶版本控制状态,即启用

  • ListObjects - 它能够列出存储桶对象

  • DeleteObjects - 它能够删除存储桶对象(但它只是将“删除标记”添加到每个对象的最新版本。对象的版本历史仍然保持未删除)

  • DeleteBucket:此操作失败并显示错误消息:

“BucketNotEmpty:您尝试删除的存储桶不为空。
您必须删除存储桶中的所有版本。”

您能否建议如何强制删除S3 存储桶中所有对象的所有版本,以便我最终可以使用 删除整个存储桶aws-sdk-go


泛舟湖上清波郎朗
浏览 283回答 2
2回答

慕斯709654

根据文档,DeleteBucket状态,必须先删除存储桶中的所有对象(包括所有对象版本和删除标记),然后才能删除存储桶本身。现在,要从启用版本控制的存储桶中删除版本,我们可以使用DeleteObject,其中指出,要删除特定版本,您必须是存储桶所有者并且必须使用版本 ID 子资源。使用此子资源会永久删除该版本。使用DeleteObjects,类似地指出,在 XML 中,如果要从启用版本控制的存储桶中删除对象的特定版本,您可以提供对象键名称和可选的版本 ID。在使用以下命令(先决条件 - Docker、Docker Compose、AWS CLI)创建存储桶并使用包含版本的文件填充它之后,我整理了一个示例程序,并针对LocalStack进行了测试。curl -O https://raw.githubusercontent.com/localstack/localstack/master/docker-compose.ymlexport SERVICES="s3"docker-compose upexport AWS_ACCESS_KEY_ID="test"export AWS_SECRET_ACCESS_KEY="test"export AWS_DEFAULT_REGION="us-east-1"aws --endpoint-url=http://localhost:4566 s3 mb s3://testbucketaws --endpoint-url=http://localhost:4566 s3api put-bucket-versioning --bucket testbucket --versioning-configuration Status=Enabledfor i in 1 2 3; do    aws --endpoint-url=http://localhost:4566 s3 cp main.go s3://testbucket/main.go    aws --endpoint-url=http://localhost:4566 s3 cp go.mod s3://testbucket/go.moddoneaws --endpoint-url=http://localhost:4566 s3api list-object-versions --bucket testbucket运行前设置以下环境变量export AWS_ENDPOINT="http://localhost:4566"export S3_BUCKET="testbucket"package mainimport (    "context"    "fmt"    "log"    "os"    "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/aws-sdk-go-v2/service/s3/types")type s3Client struct {    *s3.Client}func main() {    awsEndpoint := os.Getenv("AWS_ENDPOINT")    bucketName := os.Getenv("S3_BUCKET")    cfg, err := config.LoadDefaultConfig(context.TODO(),        config.WithEndpointResolverWithOptions(aws.EndpointResolverWithOptionsFunc(            func(service, region string, options ...interface{}) (aws.Endpoint, error) {                return aws.Endpoint{                    URL:               awsEndpoint,                    HostnameImmutable: true,                }, nil            })),    )    if err != nil {        log.Fatalf("Cannot load the AWS configs: %s", err)    }    serviceClient := s3.NewFromConfig(cfg)    client := &s3Client{        Client: serviceClient,    }    fmt.Printf(">>> Bucket: %s\n", bucketName)    objects, err := client.listObjects(bucketName)    if err != nil {        log.Fatal(err)    }    if len(objects) > 0 {        fmt.Printf(">>> List objects in the bucket: \n")        for _, object := range objects {            fmt.Printf("%s\n", object)        }    } else {        fmt.Printf(">>> No objects in the bucket.\n")    }    if client.versioningEnabled(bucketName) {        fmt.Printf(">>> Versioning is enabled.\n")        objectVersions, err := client.listObjectVersions(bucketName)        if err != nil {            log.Fatal(err)        }        if len(objectVersions) > 0 {            fmt.Printf(">>> List objects with versions: \n")            for key, versions := range objectVersions {                fmt.Printf("%s: ", key)                for _, version := range versions {                    fmt.Printf("\n\t%s ", version)                }                fmt.Println()            }        }        if len(objectVersions) > 0 {            fmt.Printf(">>> Delete objects with versions.\n")            if err := client.deleteObjects(bucketName, objectVersions); err != nil {                log.Fatal(err)            }            objectVersions, err = client.listObjectVersions(bucketName)            if err != nil {                log.Fatal(err)            }            if len(objectVersions) > 0 {                fmt.Printf(">>> List objects with versions after deletion: \n")                for key, version := range objectVersions {                    fmt.Printf("%s: %s\n", key, version)                }            } else {                fmt.Printf(">>> No objects in the bucket after deletion.\n")            }        }    }    fmt.Printf(">>> Delete the bucket.\n")    if err := client.deleteBucket(bucketName); err != nil {        log.Fatal(err)    }}func (c *s3Client) versioningEnabled(bucket string) bool {    output, err := c.GetBucketVersioning(context.TODO(), &s3.GetBucketVersioningInput{        Bucket: aws.String(bucket),    })    if err != nil {        return false    }    return output.Status == "Enabled"}func (c *s3Client) listObjects(bucket string) ([]string, error) {    var objects []string    output, err := c.ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input{        Bucket: aws.String(bucket),    })    if err != nil {        return nil, err    }    for _, object := range output.Contents {        objects = append(objects, aws.ToString(object.Key))    }    return objects, nil}func (c *s3Client) listObjectVersions(bucket string) (map[string][]string, error) {    var objectVersions = make(map[string][]string)    output, err := c.ListObjectVersions(context.TODO(), &s3.ListObjectVersionsInput{        Bucket: aws.String(bucket),    })    if err != nil {        return nil, err    }    for _, object := range output.Versions {        if _, ok := objectVersions[aws.ToString(object.Key)]; ok {            objectVersions[aws.ToString(object.Key)] = append(objectVersions[aws.ToString(object.Key)], aws.ToString(object.VersionId))        } else {            objectVersions[aws.ToString(object.Key)] = []string{aws.ToString(object.VersionId)}        }    }    return objectVersions, err}func (c *s3Client) deleteObjects(bucket string, objectVersions map[string][]string) error {    var identifiers []types.ObjectIdentifier    for key, versions := range objectVersions {        for _, version := range versions {            identifiers = append(identifiers, types.ObjectIdentifier{                Key:       aws.String(key),                VersionId: aws.String(version),            })        }    }    _, err := c.DeleteObjects(context.TODO(), &s3.DeleteObjectsInput{        Bucket: aws.String(bucket),        Delete: &types.Delete{            Objects: identifiers,        },    })    if err != nil {        return err    }    return nil}func (c *s3Client) deleteBucket(bucket string) error {    _, err := c.DeleteBucket(context.TODO(), &s3.DeleteBucketInput{        Bucket: aws.String(bucket),    })    if err != nil {        return err    }    return nil}请注意,在listObjectVersions方法中,我将VersionIds 与Keys 映射。    for _, object := range output.Versions {        if _, ok := objectVersions[aws.ToString(object.Key)]; ok {            objectVersions[aws.ToString(object.Key)] = append(objectVersions[aws.ToString(object.Key)], aws.ToString(object.VersionId))        } else {            objectVersions[aws.ToString(object.Key)] = []string{aws.ToString(object.VersionId)}        }    }然后在deleteObjects方法中,当传递ObjectIdentifiers 时,我为一个对象的所有版本传递了 sKey和ObjectIds。    for key, versions := range objectVersions {        for _, version := range versions {            identifiers = append(identifiers, types.ObjectIdentifier{                Key:       aws.String(key),                VersionId: aws.String(version),            })        }    }

繁华开满天机

使用 golang sdk 这似乎是不可能的。他们没有实现删除版本功能。
随时随地看视频慕课网APP

相关分类

Go
我要回答