我有一个启用了版本控制的Amazon S3存储桶。由于生命周期策略配置错误,此存储桶中的许多对象都添加了删除标记。
我可以从S3控制台中删除这些标记以恢复这些对象的先前版本,但是有足够的对象可以在Web控制台上手动执行此操作非常耗时。
有没有办法在S3存储桶中找到所有删除标记并删除它们,还原该存储桶中的所有文件?理想情况下,我想从控制台本身做到这一点,虽然我很乐意写一个脚本或使用amazon CLI工具来做到这一点,如果这是唯一的方法。
谢谢!
答案 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)
您需要编写一个程序:
使用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
]);
}
}
}
有关脚本的一些注意事项:
答案 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