🚮

S3で一括復元する方法 (削除マーカーを一括削除)

2023/10/04に公開

初めに

この記事は以下の様に versioning が効いた S3 バケットで誤って一括削除をしてしまった時に、削除マーカーをprefixで指定して削除して、一括で復元する方法を紹介します。
悲劇

code

以下のコードで、prefixで指定した削除マーカーを削除します。
(動作確認をしておりますが、for文と削除があるので、ご使用は気を付けてください)

import boto3


def delete_delete_markers_for_prefix(bucket_name: str, prefix: str):
    s3 = boto3.client("s3")
    key_marker = None
    version_id_marker = None
    while True:
        if key_marker is None and version_id_marker is None:
            response = s3.list_object_versions(
                Bucket=bucket_name,
                Prefix=prefix,
            )
        else:
            response = s3.list_object_versions(
                Bucket=bucket_name,
                Prefix=prefix,
                KeyMarker=key_marker,
                VersionIdMarker=version_id_marker,
            )

        # 削除マーカーのリストを取得して、それぞれのマーカーを削除
        delete_markers = response.get("DeleteMarkers", [])
        for delete_marker in delete_markers:
            object_key = delete_marker["Key"]
            version_id = delete_marker["VersionId"]
            s3.delete_object(Bucket=bucket_name, Key=object_key, VersionId=version_id)
            print(f"Deleted delete marker for {object_key} (Version: {version_id})")

        ### is truncated が True の場合、まだデータが残っているのでページネーションを行う。
        if response.get("IsTruncated", False):
            key_marker = response.get("NextKeyMarker")
            version_id_marker = response.get("NextVersionIdMarker")
        else:
            break  # 全てのオブジェクトの情報を取得した場合、ループを終了


bucket_name = "bucket_name"
prefix = "prefix"
delete_delete_markers_for_prefix(bucket_name, prefix)

あとがき

まとめ

  • s3 のファイル操作では、高レベルAPIを仕様することが推奨されております。
    (高レベルオブジェクトを使うと、list object などは、ページネーションが必要なかったりうれしいことがたくさんあります。)
  • だが高レベルAPIでは、削除マーカーを取得することができず、この方法となりました。(知っている方いたら教えてください)
  • list_object では NextToken 一つだったものが、二つになったり色々と複雑でしたが勉強になりました。

参考

Discussion