AWS Glacierのファイルを通常S3に戻すためのPythonスクリプトを書きました

先日、AWS S3のGlacierに保存している写真をダウンロードしたい機会がありまして。AWSのコンソールでポチポチとS3アーカイブに戻すのが面倒だったので複数ファイルをまとめてGlacierからS3に戻すためのスクリプトを書きました。

環境

実行環境は以下。

  • Windows 8.1
  • Python 3.3
  • aws-cli 1.6.10

aws-cliとはCUIでAWSを操作できるインタフェースです。詳細は後ほど。

仕組み

仕組みとしては、Pythonスクリプト経由でaws-cliのコマンド叩き、返り値(JSON)をもとにS3アーカイブにリストアするリクエストを送る、という形です。

Python-AWS-S3-Glacier

aws-cliの準備

awsをコマンドラインで操作するためのインタフェースをインストールします。Pipがインストールされているのであれば下記のコマンドでいけます。

$ pip install awscli

次に初期設定を行います。aws configureを実行してください。すると以下のように対話的になります。求められている必要情報を入力します。

$ aws configure
AWS Access Key ID [None]: [アマゾンのアクセスキーIDを入力]
AWS Secret Access Key [None]: [シークレットアクセスキーを入力]
Default region name [None]: [S3で利用しているregionを入力(下記参照)]
Default output format [None]: json

Access Key ID と Secret Access Keyについて

もし手元にAccess Keyを持っていなければ新規に発行する必要があります。また、過去に作ったことがあるものの忘れてしまったという人も新規に発行してください(再発行されないはず)。

発行方法は以下のURLが詳しいです。

リージョン情報について

リージョン情報はTOKYOという表記では認識されません。以下のリンク先にRegion Name とRegionの対応表がありますので、ここで記載されているRegionの項のラベルをご利用ください。

対応表
http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region

東京リージョン場合、Asia Pacific (Tokyo)ですからap-northeast-1とすればOKです。 自分のS3(というかbucket)がどこのリージョンか解らない場合はAWSのコンソール上で確認できます(下図)。

aws console

もし複数のbucketを持っており、それぞれ違うリージョンを利用している場合は主に利用したいリージョンを一旦選択してください。

「え?」と思うかもしれませんが、 aws configureで入力したリージョン情報はC:\Users\[User]\.aws\configに保存されており、後ほど変更できます。また、スクリプトを実行する際に、個別でリージョンは指定できるようにしてあります。

aws-cliをテストする

aws-cliがきちんと動作するかは以下のコマンドで確認できます。

aws s3api list-objects --bucket [バケット名]

上手くいけば以下のようなファイル情報を表したJSONが返ってくるはずです。

{
   "Key": "[path]/[file]",
   "LastModified": "2013-11-04T14:12:44.000Z",
   "ETag": "\"0704275f684xxxxxxxxabbc13804a\"",
   "Owner": {
       "ID": "14f61c0fdadfasuoifdsa89fdsa089d0a8s9d0fa8s90afdsa5b3e",
       "DisplayName": "[xxxxxxxxxxxxxxx]"
   },
   "StorageClass": "GLACIER",
   "Size": 1306686
},

PythonからRestore Requestを叩く

aws-cliが準備できたらリストアリクエストを送ります。 以下のスクリプトを利用します。

# -*- coding:utf-8 -*-
import subprocess 
import json

# 以下の変数にbucket名を記述
bucket = ''


# 以下の変数にbucket内のフォルダパスを記述
# 例)[bucket名]/picture/sample/ であれば 'picture/sample'
path = ''

# 以下の変数にbucketのリージョンを記述
# 何も入力しないとaws-cliの設定で入力したregionが自動で選択されます
region = ''

def main():
    list_cmd = ('aws s3api list-objects '
                '--bucket "{0}" --prefix "{1}" '
                '--output json ')
    
    if region != '':
        list_cmd += '--region "{0}"'.format(region)
                
    list_cmd = list_cmd.format(bucket, path)

    print('-' * 80)
    print(list_cmd)
    print('-' * 80)

    json_str = subprocess.check_output(list_cmd , shell=True)
    json_str = json_str.decode('cp932')
    json_obj = json.loads(json_str)

    for content in json_obj['Contents']:
        key = content['Key']
        print("Key=" + key)

        restore_cmd = ('aws s3api restore-object '
                       '--bucket "{0}" --key "{1}" '
                       '--restore-request Days=1 ')

        if region != '':
            restore_cmd += '--region "{0}"'.format(region)
        
        restore_cmd = restore_cmd.format(bucket, key)
        response    = subprocess.check_output(restore_cmd, shell=True)


if __name__ == '__main__':
  main()

実行した際にもしこんなエラーが出たらbucketのリージョンが間違っていると思われます。

A client error (PermanentRedirect) occurred when calling the RestoreObject operation: The bucket you are attempting to a
ccess must be addressed using the specified endpoint. Please send all future requests to this endpoint: s3.amazonaws.com

You can fix this issue by explicitly providing the correct region location using the --region argument, the AWS_DEFAULT_
REGION environment variable, or the region variable in the AWS CLI configuration file.  You can get the bucket's locatio
n by running "aws s3api get-bucket-location --bucket BUCKET".

この場合は以下のコマンドでbucketのリージョンを確認してください。

$ aws s3api get-bucket-location --bucket [バケット名]
{
    "LocationConstraint": "ap-northeast-1"
}

上記コマンドでリージョンの値がNullだったら、それはStandard Regionを意味しており、リージョンはus-east-1( もしくはus-west-1)となります(参考:Leveraging the s3 and s3api Commands)。

リクエストを出したら、だいたい1~2時間後くらいに通常のbucketに戻されます。そしたらまとめてダウンロードできます。

以上です。