S3 Glacierの状態を確認してみた。

# 1. はじめに

2年目に突入したエンジニアをしているものです。

**ARIのアドベンドカレンダ3日目の記事となります！**

https://qiita.com/advent-calendar/2023/ari-group

昨年に引き続き、今年も参加することになりましたので備忘録を、、
最近初めてS3 Glacierを扱う機会がありましたのでその時の経験と考え方と気づきをまとめます。

# 2. S3 Glacierとは

> Amazon S3 Glacier ストレージクラス は、データアーカイブ専用に設計されており、クラウドで最高のパフォーマンス、最高の検索の柔軟性、最低のコストのアーカイブストレージを提供します。さまざまなアクセスパターンやストレージ期間に最適化された 3 種類のアーカイブストレージクラスから選択できるようになりました。

https://aws.amazon.com/jp/s3/storage-classes/glacier/

AWSについて勉強すると名前だけは知っている状態になるS3 Glacier。
主にアーカイブ用に長期間ファイルを置くのに向いたサービスということだけ知っている状態でした。

今回扱ったのは、3つ用意されているうち真ん中の「S3 Glacier Flexible Retrieval(旧 S3 Glacier)」です。

:::note info
私が覚えたときは単に「S3 Glacier」というストレージクラスだった気がするのですが、いつのまにか呼称が変わってました…
:::

特徴としては下記の通り。

- ストレージ料金： 0.0045USD/GB
- 取得時間：1分～12時間（3種類の取り出しオプション）
- 最小ストレージ期間： 90日

そして、アーカイブ用であるが故の最大の(?)注意点はこれです。

> 最小ストレージ期間が経過する前にオブジェクトが削除されたり、上書きされたり、別のストレージクラスに移行されたりした場合、通常のストレージ利用料金に加えて、その最小ストレージ期間の残りのストレージ料金が日割りで請求されます。
最小ストレージ期間より長く保存されたオブジェクトについては、最小ストレージ料金が発生しません。

https://aws.amazon.com/jp/s3/pricing/

すなわち、「S3 Glacier Flexible Retrieval」を使う場合は90日以上保管しないと無駄に費用が掛かってしまうということですね。

# 3. 本題

S3 Glacierについて簡単に確認したところで、本題に入ろうと思います。
（穴だらけな内容ですが今回自分で設計したわけではないのでこれくらいで許してください。）

今回やりたかったこととしては、S3 Glacier Flexible Retrieval（以下、S3 Glacierとします。）に置かれたzipファイルの中身を編集して再度アーカイブとしてアップする処理をLambdaで作ろうというものでした。

## 3.1. 当初の構成

```plantuml
Lambda<-S3Glacier : zipを取得
Lambda->S3Glacier : 編集したzipをアップ
```

当初受け取った設計では上記のように、単一のLambdaから処理を完結させる構成を想定しているようでした。
しかし、冒頭で記載した通りS3 Glacierからオブジェクトを取得するのには時間がかかります。
なるべくコストをかけないようにする場合は5~12時間かかるので、とてもLambdaの処理時間内では不可能です。
> 取得時間：1分～12時間（3種類の取り出しオプション）

また、取得時間とはいっても実際にファイルを取得するのに時間がかかるわけではなく、
アーカイブされた状態からS3 Standardと同じようにオブジェクトを取得できる状態にするための復元(restore)処理に時間がかかる様でした。
ということで、

## 3.2. 修正後の構成
```plantuml
Lambda1->S3Glacier : zipに復元リクエスト
S3Glacier->Lamnbda2 : 復元完了イベント
S3Glacier->Lamnbda2 : zipを取得
S3Glacier<-Lamnbda2 : 編集したzipをアップ
```
何が何でもLambdaでやりたかったので、前段後段に分かれたこのような構成を考えました。
これならうまく動かせそうです。

## 3.3. 次の問題

復元リクエストは絶賛復元中のオブジェクトに対してリクエストを出すとエラーとなる用でした。
重複リクエストもありえるので、これではまずい。
ということで、**Lambda1**からリクエストを投げる前にオブジェクトの状態を確認したい。

また、zipファイルは作成当初S3 Standardで置かれ、ライフサイクルポリシーを用いて数日後にS3 Glacierに移行するような構成だったので、その状態についても一緒に確認できると嬉しい。

ということで、下記の関数でオブジェクトの情報を取得したところ様々なことがわかりました。
```python
import boto3

s3 = boto3.client('s3')
response = s3.client.head_object(
    Bucket='bucket_name',
    Key='key'
)
```

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3/client/head_object.html

S3 Standardのオブジェクト、S3 Glacierのオブジェクト、復元中、復元完了状態に対してresponseを確認しました。

```json:S3 Standardのオブジェクト
{
    "ResponseMetadata": {
        "RequestId": "XXXXXXXXXXXXXXXX",
        "HostId": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
        "HTTPStatusCode": 200,
        "HTTPHeaders": {
            "x-amz-id-2": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
            "x-amz-request-id": "ZZZZZZZZZZZZ",
            "date": "Mon, 4 Des 2023 00:00:00 GMT",
            "last-modified": "Mon, 4 Des 2023 00:00:00 GMT",
            "etag": "eeeeeeeeeeeeeeeeeeeeeeeeeeee",
            "x-amz-server-side-encryption": "aaaaaa",
            "accept-ranges": "bytes",
            "content-type": "application/zip",
            "server": "AmazonS3",
            "content-length": "12092"
        },
        "RetryAttempts": 0
    },
    "AcceptRanges": "bytes",
    "LastModified": "datetime.datetime(2023,12,4,0,0,0, tzinfo=tzutc())",
    "ContentLength": 12092,
    "ETag": "eeeeeeeeeeeeeeeeeeeeeeeeeeee",
    "ContentType": "application/zip",
    "ServerSideEncryption": "aaaaaa",
    "Metadata": {}
}
```
以下、Standardとの差分です。（コメントは追加しています）
```json:S3 Glacierのオブジェクト
      :
            // ResponseMetadata内のストレージクラス情報
            "x-amz-storage-class": "GLACIER",
      :
    // ストレージクラス情報
    "StorageClass": "GLACIER"
}
```

```json:復元中のS3 Glacierオブジェクト
      :
            // 復元リクエスト情報
            // 復元中
            "x-amz-restore": "ongoing-request=true",
            // 復元開始日時
            "x-amz-restore-request-date": "Mon, 4 Des 2023 00:10:00 GMT",
            // 復元期間（復元完了後どれだけ保持するか）
            "x-amz-restore-expiry-days": "1",
            // 復元オプション
            "x-amz-restore-tier": "Standard",
      :
            // ResponseMetadata内のストレージクラス情報
            "x-amz-storage-class": "GLACIER",
      :
    // 復元中
    "Restore": "ongoing-request=true",
      :
    // ストレージクラス情報
    "StorageClass": "GLACIER"
}
```

```json:復元完了したS3 Glacierオブジェクト
      :
            // 復元完了、復元状態終了日時
            "x-amz-restore": "ongoing-request=false, expiry-date=Tus, 5 Des 2023 00:00:00 GMT",
      :
            // タグカウント
            "x-amz-tagging-count": "1",
            // ResponseMetadata内のストレージクラス情報
            "x-amz-storage-class": "GLACIER",
      :
    // 復元完了、復元状態終了日時 
    "Restore": "ongoing-request=false, expiry-date=Tus, 5 Des 2023 00:00:00 GMT",
      :
    // ストレージクラス情報
    "StorageClass": "GLACIER"
}
```

ふむふむ、、
**StorageClass**と**Resotre**の値をみることで「S3 Glacierになっているか」、「復元状態はどうか」を確認できますね。

・StorageClass
> Provides storage class information of the object. Amazon S3 returns this header for all objects except for S3 Standard storage class objects.

・Restore
> If the object is an archived object (an object whose storage class is GLACIER), the response includes this header if either the archive restoration is in progress (see RestoreObject or an archive copy is already restored.
> If an archive copy is already restored, the header value indicates when Amazon S3 is scheduled to delete the object copy. For example:


これで、目下の問題は解決しました！！

# 最後に

ここまで読んでくださった方、ありがとうございます。

今回も前回に引き続き、自分用の記録という意味合いが大きく、かなり見づらいものになってしまったかと思ってます。

次回以降はもう少し読者に寄り添ったものをと考えてます…