カピバラ好きなエンジニアブログ

興味ある技術とか検証した内容を赴くままに書いていきます。カピバラの可愛さこそ至高。

Glacierから復元するスクリプトを作ってみた

はじめに

普段S3を使用する時、長期間の保管が必要でかつアクセスが少ないデータに対しては、ライフサイクルルールを使用してGlacierに移動している方が多いと思います。

Glacierはストレージコストが低い分最低保存期間が決まっていたり、S3に復元する際に別途費用が掛かったり色々と制限がありますが、今回はその復元方法について書いていきます。

Glacierを使用する要件がある時点で、そこから復元する機会というのは中々ないとは思いますが、いざ復元を使用しようと思ったときに、1ファイルだけ復元するだけでなく、このフォルダ階層配下をまとめて復元したい、なんてこともあるのではないでしょうか。

しかし、コンソール上から復元しようとした場合、以下の通りフォルダごとまとめての復元はできず、

f:id:live-your-life-dd18:20191204155851p:plain

以下のように復元対象のファイルをすべて選択して復元操作をする必要があります。

f:id:live-your-life-dd18:20191204155955p:plain

そこで、今回はCLIで指定したフォルダ配下のオブジェクトをまとめて復元するスクリプトを作ってみました。

一応調べてみると、既に先人の方々が似たようなことをやっているような記事は見つけました。

qiita.com

ただ、Pythonスクリプトや非公式のツールを使用した復元手順はあるものの、AWS CLIスクリプトを組んでみたみたいなのはなさそうだったので、今回はそこにフォーカスを当ててやってみました。

あと個人的に最近Windows Server にCloudBerry DriveでS3をマウントして使用することが多いので、Windowsで使う想定でAWS CLIPowerShellにしています。

実施内容

実施作業

使用コマンドとスクリプト構成

AWS CLIでS3を操作するときに、aws s3コマンドとaws s3apiコマンドの2種類ありますが、今回はGlacierからの復元を行うので、後者のaws s3apiコマンドを使用します。

docs.aws.amazon.com

s3apiのリファレンスはこちら
docs.aws.amazon.com

スクリプトの構成としては、以下を想定しています。
バケット名、復元対象のパス、復元期間(日)、復元方法(Standard ,Bulk ,Expedited)をパラメータで指定
②指定パス配下の全オブジェクト取得処理
③オブジェクトごとにストレージクラス及び復元判定処理
④復元中でなければ復元リクエスト送信処理


使用コマンド確認

スクリプトを作成する前に、実行するコマンドを確認しておきます。

特定バケット配下のオブジェクト取得コマンド

  • コマンド
aws s3api list-objects-v2 --bucket test-tmp-windows --prefix test1/test1-1/
  • 実行結果
    f:id:live-your-life-dd18:20191204164214p:plain

オブジェクトのストレージクラス及びリストアステータス取得コマンド

  • コマンド
aws s3api head-object --bucket test-tmp-windows --key test1/test1-1/test1.txt

復元リクエスト送信コマンド

  • コマンド
aws s3api restore-object --bucket test-tmp-windows --key test1/test1-1/test1.txt --restore-request '{\"Days\":1,\"GlacierJobParameters\":{\"Tier\":\"Standard\"}}'
  • 実行結果
    f:id:live-your-life-dd18:20191204164255p:plain


スクリプトの実行対象

作成したスクリプトを実行する環境は以下の構成です。
スクリプトを実行したら2つのtxtファイルがGlacierから復元中になる想定です。

PS C:\Users\Administrator> aws s3api list-objects-v2 --bucket test-tmp-windows  --prefix test
{
    "Contents": [
        {
            "Key": "test/",
            "LastModified": "2019-12-06T14:23:24.000Z",
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            "Size": 0,
            "StorageClass": "STANDARD"
        },
        {
            "Key": "test/test1/",
            "LastModified": "2019-12-06T14:23:34.000Z",
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            "Size": 0,
            "StorageClass": "STANDARD"
        },
        {
            "Key": "test/test1/Test.txt",
            "LastModified": "2019-12-06T14:25:59.000Z",
            "ETag": "\"3f0326f4e56c3f4b54feede9071cafbf\"",
            "Size": 6,
            "StorageClass": "GLACIER"
        },
        {
            "Key": "test/test1/test1-1/",
            "LastModified": "2019-12-06T14:23:40.000Z",
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            "Size": 0,
            "StorageClass": "STANDARD"
        },
        {
            "Key": "test/test1/test1-1/test1-1.txt",
            "LastModified": "2019-12-06T14:26:13.000Z",
            "ETag": "\"3f0326f4e56c3f4b54feede9071cafbf\"",
            "Size": 6,
            "StorageClass": "GLACIER"
        }
    ]
}



作成したスクリプト

説明したコマンドを使用して以下のスクリプトを作成します。

Param(
    [parameter(mandatory=$true)][String]$s3_bucket,   # S3バケット名
    [parameter(mandatory=$true)][String]$s3_prefix,   # バケット配下パス
    [parameter(mandatory=$true)][String]$restore_day, # 復元期間
    [parameter(mandatory=$true)][String]$restore_type # 復元方法
)

$obj_list=aws s3api list-objects-v2 --bucket $s3_bucket --prefix $s3_prefix | ConvertFrom-Json

$restore_op="'{\`"Days\`":" + ${restore_day} + ",\`"GlacierJobParameters\`":{\`"Tier\`":\`"" + ${restore_type} + "\`"}}'"

if($obj_list -eq $null){
  echo "オブジェクトの取得に失敗しました"
  exit 1
}

foreach( $obj in $obj_list.Contents){
  $path=$obj.key
  $last_str=$path.Substring($path.Length - 1, 1)
  if($last_str -ne "/"){

    $file_data=aws s3api head-object --bucket $s3_bucket --key $path | ConvertFrom-Json

    echo "$path"

    if($file_data.StorageClass -eq "GLACIER"){

      $cmd="aws s3api restore-object --bucket " + $s3_bucket + " --key $path --restore-request $restore_op"

      if($file_data.Restore -ne $null){
        echo "ファイルは復元中です"
        continue
      } else {
        echo "復元リクエスト送信しました"
        invoke-expression $cmd

        if($? -eq $false){
          echo "コマンドが失敗しました"
          exit 1
        }
      }
    } else {
      echo "ストレージタイプがGlacierではありません"
      continue
    }
  }
}



実行結果

スクリプトを実行したら以下のようになりました。

PS C:\Users\Administrator\Desktop\tool> .\glacier_restore.ps1

コマンド パイプライン位置 1 のコマンドレット glacier_restore.ps1
次のパラメーターに値を指定してください:
s3_bucket: test-tmp-windows
s3_prefix: test
restore_day: 1
restore_type: Standard
test/test1/Test.txt
復元リクエスト送信しました
test/test1/test1-1/test1-1.txt
復元リクエスト送信しました

想定通りエラーなくtxtファイルのみに復元リクエストが送信されています。
S3上でも確認したところステータスが復元中になっていることが確認できました。

f:id:live-your-life-dd18:20191206233519p:plain
f:id:live-your-life-dd18:20191206233534p:plain


感想及び所感

ということで、Glacierからの復元をAWS CLIPowerShellで作成してみました。
状況によってはサーバにPythonをインストールできなかったりするので、もし良かったら試してみてください。