2 回答

TA貢獻(xiàn)1840條經(jīng)驗(yàn) 獲得超5個(gè)贊
根據(jù)文檔,DeleteBucket狀態(tài),
必須先刪除存儲(chǔ)桶中的所有對(duì)象(包括所有對(duì)象版本和刪除標(biāo)記),然后才能刪除存儲(chǔ)桶本身。
現(xiàn)在,要從啟用版本控制的存儲(chǔ)桶中刪除版本,我們可以
使用DeleteObject,其中指出,
要?jiǎng)h除特定版本,您必須是存儲(chǔ)桶所有者并且必須使用版本 ID 子資源。使用此子資源會(huì)永久刪除該版本。
使用DeleteObjects,類似地指出,
在 XML 中,如果要從啟用版本控制的存儲(chǔ)桶中刪除對(duì)象的特定版本,您可以提供對(duì)象鍵名稱和可選的版本 ID。
在使用以下命令(先決條件 - Docker、Docker Compose、AWS CLI)創(chuàng)建存儲(chǔ)桶并使用包含版本的文件填充它之后,我整理了一個(gè)示例程序,并針對(duì)LocalStack進(jìn)行了測(cè)試。
curl -O https://raw.githubusercontent.com/localstack/localstack/master/docker-compose.yml
export SERVICES="s3"
docker-compose up
export 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://testbucket
aws --endpoint-url=http://localhost:4566 s3api put-bucket-versioning --bucket testbucket --versioning-configuration Status=Enabled
for 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.mod
done
aws --endpoint-url=http://localhost:4566 s3api list-object-versions --bucket testbucket
運(yùn)行前設(shè)置以下環(huán)境變量
export AWS_ENDPOINT="http://localhost:4566"
export S3_BUCKET="testbucket"
package main
import (
"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
}
請(qǐng)注意,在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方法中,當(dāng)傳遞ObjectIdentifiers 時(shí),我為一個(gè)對(duì)象的所有版本傳遞了 sKey和ObjectIds。
for key, versions := range objectVersions {
for _, version := range versions {
identifiers = append(identifiers, types.ObjectIdentifier{
Key: aws.String(key),
VersionId: aws.String(version),
})
}
}

TA貢獻(xiàn)1816條經(jīng)驗(yàn) 獲得超4個(gè)贊
使用 golang sdk 這似乎是不可能的。他們沒(méi)有實(shí)現(xiàn)刪除版本功能。
- 2 回答
- 0 關(guān)注
- 352 瀏覽
添加回答
舉報(bào)