How to Remove Delete Markers from Multiple Objects on Amazon S3 at once
Use this to restore the files inside the specific folder. I've used aws cli commands in my script. Provide input as: 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
Edit: put $VERSION_ID
in correct position in the script
Here's a sample Python implementation:
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()
For some context for this answer see: https://docs.aws.amazon.com/AmazonS3/latest/dev/DeleteMarker.html
If you try to get an object and its current version is a delete marker, Amazon S3 responds with:
- A 404 (Object not found) error
- A response header, x-amz-delete-marker: true
The response header tells you that the object accessed was a delete marker. This response header never returns false; if the value is false, Amazon S3 does not include this response header in the response.
The only way to list delete markers (and other versions of an object) is by using the versions subresource in a GET Bucket versions request. A simple GET does not retrieve delete marker objects.
Unfortunately, despite what is written in https://github.com/boto/botocore/issues/674, checking if ObjectVersion.size is None
is not a reliable way to determine if a version is a delete marker as it will also be true for previously deleted versions of folder keys.
Currently, boto3 is missing a straightforward way to determine if an ObjectVersion
is a DeleteMarker. See https://github.com/boto/boto3/issues/1769
However, ObjectVersion.head()
and .Get()
operations will throw an exception on an ObjectVersion
that is a DeleteMarker. Catching this exception is likely the only reliable way of determining if an ObjectVersion
is a DeleteMarker.
I just wrote a program (using boto) to solve the same problem:
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)
If you need to restore folders within the versioned buckets, the rest of the program I wrote can be found here.