銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

Amazon Glacier に保存しているアーカイブのIDを忘れたら、削除するのも大変だった件

1年半ほど前に家族の写真とか100GB~(将来的に)1TB程度のファイルをどこにバックアップしようかなと思って、Amazon Glacierを使い始めました。 しかし、Glacierの課金体系などを完全には理解しておらず、いざ復元するときに使いづらいことがわかったので使うのをやめることにしました。 課金体系というのは特にデータ復元時のコストで、この辺とかに書かれています。

takatoshiono.hatenablog.com

現在では設定で無料の枠内に収まるようなレートを強制することができるようです。

f:id:tanaka733:20151004220708p:plain

とはいえいろいろ扱いづらいなあと思っていたので、最近ではOneDriveを主なバックアップ先として使っています。Windows10でデグレしましたがExplorerと統合されていますし、異なるアカウントで共有するのも簡単です。もろもろのキャンペーンで400GBほど無料で使っていますが、将来課金が必要になった場合でも許容範囲と判断しています。

で、Glacierの方ですが、使わなくなったので、月100円未満ですが削除することにしました。3か月以内に削除すると追加課金されますが、すでに1年半も経過しているので課金されることもないでしょう*1

で、Management Consoleから Vaultを削除しようとしましたが、空じゃないと削除できません。なのでアーカイブを先に削除する必要があります。

docs.aws.amazon.com

そしてアーカイブを削除するにはアーカイブIDが必要なのですが、これは本来手元で管理・保存しておくもの*2で、Vaultに含まれるアーカイブIDをすぐに取得する方法はありません。ジョブの実行をAPIで依頼して数時間ほど待つ必要があります。

docs.aws.amazon.com

これらの操作はAPIを実行しないといけないので、AWS SDK for .NET を使ってLINQPadから実行することにしました。まずはアーカイブ一覧データを作成するためのジョブの実行。LINQPadなのでDumpメソッドで出力していますが、コンソールアプリならConsole.WriteLineなどに変えてください。

var vaultName = "<Vaultの名前>";
var client = new AmazonGlacierClient("<AccessKey>",
    "<SecretAccessKey>",
    Amazon.RegionEndpoint.APNortheast1);

var initJobRequest = new InitiateJobRequest()
{
    VaultName = vaultName,
    JobParameters = new JobParameters()
    {
        Type = "inventory-retrieval",
        SNSTopic = "<ジョブの完了を通知するSNSのARN>",
    }
};
var initJobResponse = client.InitiateJob(initJobRequest);
var jobId = initJobResponse.JobId.Dump();

ジョブが完了したらSNSに通知がいきますが、ジョブの進捗どうですかを知りたい場合もAPIから聞けます。

var jobId = "<出力したJobId>";
var jobOutput = client.DescribeJob(new DescribeJobRequest
{
    VaultName = vaultName,
    JobId = jobId
});
jobOutput.Dump();

完了通知が来たら、ジョブの結果を取得して、その中身にあるアーカイブIDを使って1つずつ削除します。JSON.NET 使ってjsonをパースしています。

var getJobOutputRequest = new GetJobOutputRequest()
{
    JobId = jobId,
    VaultName = vaultName
};

var getJobOutputResponse = client.GetJobOutput(getJobOutputRequest);
string str;
using (var webStream = getJobOutputResponse.Body)
{
    using (var stream = new MemoryStream())
    {
        webStream.CopyTo(stream);
        stream.Flush();
        str = Encoding.UTF8.GetString(stream.GetBuffer());
    }
}

var json = JObject.Parse(str).Dump();
var manager = new ArchiveTransferManager("<AccessKey>",
    "<SecretAccessKey>",
    Amazon.RegionEndpoint.APNortheast1);
foreach (var item in (JArray)json["ArchiveList"])
{
    var id = item["ArchiveId"].Value<string>();
    item.Dump("deleting");
    manager.DeleteArchive(vaultName, id);
}

Vaultに対するインベントリの更新は24時間ごとに行われていて、最後のインベントリの更新時点でアーカイブがない(かつそれ以降にアーカイブ追加イベントがない)時だけVaultは削除できるので、しばらく待ってからVaultを削除しました。以上で作業は完了です。余計な課金がされていないことを願っています...

*1:作業中に確認する術がないのが怖い

*2:もともとCloudBerryというツールで管理していたが、OSのクリーンインストールの時に管理データを消してしまった