如何立即从Amazon S3上的多个对象中删除删除标记

时间:2015-08-19 21:39:21

标签: amazon-web-services amazon-s3 versioning

我有一个启用了版本控制的Amazon S3存储桶。由于生命周期策略配置错误,此存储桶中的许多对象都添加了删除标记。

我可以从S3控制台中删除这些标记以恢复这些对象的先前版本,但是有足够的对象可以在Web控制台上手动执行此操作非常耗时。

有没有办法在S3存储桶中找到所有删除标记并删除它们,还原该存储桶中的所有文件?理想情况下,我想从控制台本身做到这一点,虽然我很乐意写一个脚本或使用amazon CLI工具来做到这一点,如果这是唯一的方法。

谢谢!

9 个答案:

答案 0 :(得分:8)

使用此选项可还原特定文件夹中的文件。我在我的脚本中使用了aws cli命令。提供输入为: sh scriptname.sh bucketname path / to / a / folder

**Script:**
#!/bin/bash
#please provide the bucketname and path to destination folder to restore
# Remove all versions and delete markers for each object
 aws s3api list-object-versions --bucket $1 --prefix $2 --output text | 
 grep "DELETEMARKERS" | while read obj
   do
        KEY=$( echo $obj| awk '{print $3}')
        VERSION_ID=$( echo $obj | awk '{print $5}')
        echo $KEY
        echo $VERSION_ID
        aws s3api delete-object --bucket $1 --key $KEY --version-id $VERSION_ID

   done

修改:将$VERSION_ID置于脚本中的正确位置

答案 1 :(得分:7)

我刚刚编写了一个程序(使用boto)来解决同样的问题:

from boto.s3 import deletemarker
from boto.s3.connection import S3Connection
from boto.s3.key import Key

def restore_bucket(bucket_name): 
    bucket = conn.get_bucket(bucket_name)
    for version in bucket.list_versions():
        if isinstance(version, deletemarker.DeleteMarker) and version.is_latest:
            bucket.delete_key(version.name, version_id=version.version_id)

如果您需要恢复版本化存储桶中的文件夹,可以找到我编写的程序的其余部分here.

答案 2 :(得分:2)

定义变量

PROFILE="personal"
REGION="eu-west-1"
BUCKET="mysql-backend-backups-prod"

立即删除DeleteMarkers

aws --profile $PROFILE s3api delete-objects \
    --region $REGION \
    --bucket $BUCKET \
    --delete "$(aws --profile $PROFILE s3api list-object-versions \
                    --region $REGION \
                    --bucket $BUCKET \
                    --output=json \
                    --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')"

立即删除版本

aws --profile $PROFILE s3api delete-objects \
    --region $REGION \
    --bucket $BUCKET \
    --delete "$(aws --profile $PROFILE s3api list-object-versions \
                    --region $REGION \
                    --bucket $BUCKET \
                    --output=json \
                    --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')"

然后删除S3存储桶

aws --profile $PROFILE s3api delete-bucket \
    --region $REGION \
    --bucket $BUCKET

答案 3 :(得分:1)

您需要编写一个程序:

  • 遍历Amazon S3存储桶中的所有对象
  • 检索每个对象的每个版本的版本ID
  • 删除删除标记

使用SDK可以相当轻松地完成此操作,例如boto

也可以使用AWS Command-Line Interface (CLI),但您必须构建一个围绕它编写脚本以捕获ID,然后删除标记。

答案 4 :(得分:1)

几周前我一直在处理这个问题。

最后,我设法在PHP中生成了一个函数,该函数删除了前缀内文件最新版本的“已删除标记”。 就个人而言,它可以完美工作,并且通过该脚本的遍历所有前缀,我设法通过无意中删除了许多s3对象来弥补自己的错误。

我将实现留在PHP中:

private function restore_files($file)
{
    $storage = get_storage()->getDriver()->getAdapter()->getClient();
    $bucket_name = 'my_bucket_name';
    $s3_path=$file->s3_path;

    $restore_folder_path = pathinfo($s3_path, PATHINFO_DIRNAME);

    $data = $storage->listObjectVersions([
        'Bucket' => $bucket_name,
        'Prefix' => $restore_folder_path,
    ]);

    $data_array = $data->toArray();
    $deleteMarkers = $data_array['DeleteMarkers'];

    foreach ($deleteMarkers as $key => $delete_marker) {
        if ($delete_marker["IsLatest"]) {
            $objkey = $delete_marker["Key"];
            $objVersionId = $delete_marker["VersionId"];

            $delete_response = $storage-> deleteObjectAsync([
                'Bucket' => $bucket_name,
                'Key' => $objkey,
                'VersionId' => $objVersionId
            ]);
        }
    }
}

有关脚本的一些注意事项:

  1. 代码是使用Laravel Framework实现的,因此,在变量$ storage中,我仅获得了PHP SDK,而没有使用所有laravel的包装器。因此,$ storage varible是S3 SDK的客户端对象。这是我使用的documentation
  2. 该函数接收的$ file参数是一个对象,该对象的属性中包含s3_path。因此,在$ restore_folder_path变量中,我获得了对象s3路径的前缀。
  3. 最后,我在s3中获得了前缀内的所有对象。我遍历DeleteMarkers列表,并询问当前对象是否是最后删除的标记。如果是的话,我用我要删除的对象的特定ID在deleteObject函数中发布了已删除标记。 This is the way s3 documentation specify to remove the deleted marker

答案 5 :(得分:1)

上述大多数版本在大型存储桶上都非常慢,因为它们使用 delete-object 而不是 delete-objects。这是 bash 版本的一个变体,它使用 awk 一次发出 100 个请求:

编辑:刚刚看到@Viacheslav 的版本,它也使用 delete-objects 并且很好很干净,但由于行长问题会因大量标记而失败。

#!/bin/bash

bucket=$1
prefix=$2

aws s3api list-object-versions \
    --bucket "$bucket" \
    --prefix "$prefix" \
    --query 'DeleteMarkers[][Key,VersionId]' \
    --output text |
awk '{ acc = acc "{Key=" $1 ",VersionId=" $2 "}," }
     NR % 100 == 0 {print "Objects=[" acc "],Quiet=False"; acc="" }
     END { print "Objects=[" acc "],Quiet=False" }' |
while read batch; do
    aws s3api delete-objects --bucket "$bucket" --delete "$batch" --output text
done

答案 6 :(得分:0)

这是一个示例Python实现:

import boto3
import botocore

BUCKET_NAME = 'BUCKET_NAME'
s3 = boto3.resource('s3')


def main():
    bucket = s3.Bucket(BUCKET_NAME)
    versions = bucket.object_versions

    for version in versions.all():
        if is_delete_marker(version):
             version.delete()


def is_delete_marker(version):
    try:
        # note head() is faster than get()
        version.head()
        return False
    except botocore.exceptions.ClientError as e:
        if 'x-amz-delete-marker' in e.response['ResponseMetadata']['HTTPHeaders']:
            return True
        # an older version of the key but not a DeleteMarker
        elif '404' == e.response['Error']['Code']:
            return False


if __name__ == '__main__':
    main()

有关此答案的某些上下文,请参见: https://docs.aws.amazon.com/AmazonS3/latest/dev/DeleteMarker.html

  

如果您尝试获取对象并且其当前版本是删除对象   标记,Amazon S3响应:

     
      
  • A 404(找不到对象)错误
  •   
  • 响应标头,x-amz-delete-marker:是
  •   
     

响应头告诉您访问的对象是一个删除对象   标记。此响应标头从不返回false。如果值是   如果为false,则Amazon S3不会在   响应。

     

列出删除标记(以及对象的其他版本)的唯一方法   通过在GET Bucket版本请求中使用versions子资源。   简单的GET不会检索删除标记对象。

不幸的是,尽管写成https://github.com/boto/botocore/issues/674,但检查ObjectVersion.size is None是否不是确定版本是否为删除标记的可靠方法,因为对于以前删除的文件夹密钥版本也是如此

当前,boto3缺少一种简单的方法来确定ObjectVersion是否为DeleteMarker。参见https://github.com/boto/boto3/issues/1769

但是,ObjectVersion.head().Get()操作将在ObjectVersion(即DeleteMarker)上引发异常。捕获此异常可能是确定ObjectVersion是否为DeleteMarker的唯一可靠方法。

答案 7 :(得分:0)

设置生命周期规则,以在几天后将其删除。否则,每1000个对象列表将花费0.005 $。

因此,最有效的方法是设置生命周期规则。

这是逐步方法。 https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-lifecycle.html

答案 8 :(得分:0)

I checked the file size. 
Marker size is 'None'
Remove all Marker.
import boto3

default_session=boto3.session.Session(profile_name="default")
s3_re=default_session.resource(service_name="s3", region_name="ap-northeast-2")
for each_bucket in s3_re.buckets.all():
    bucket_name = each_bucket.name
    s3 = boto3.resource('s3')
    bucket = s3.Bucket(bucket_name)
    version = bucket.object_versions
    for ver in version.all():
        if str(ver.size) in 'None':
            delete_file = ver.delete()
            print(delete_file)
        else:
            pass