2012年08月31日

Amazon GlacierでArchive IDを取得する方法

Amazon Glacierを契約しました。

使い始めるにあたり、まずは自分でアップロードとダウンロードができないと始まらないので、Amazone Web ServiecのページからC#のSDKをダウンロードしました。サンプルに従って、ファイルのアップロードは問題なくできましたが、アーカイブIDを控えるのを忘れてしまい、ダウンロードも削除もできない状態になってしまいました。

SDKの説明書には、アーカイブIDの取得方法が明確に記載されていませんでしたが、AWSのフォーラムにジョブリクエストでinventory-retrievalタイプを指定すると、アーカイブIDが取得できる事が書かれていましたので試しに実装してみました。

以下、コードです。
ジョブ要求からジョブ準備完了まで、愚直に5時間待つプログラムですのでご注意ください。Amazon SNSでトピックを作成している方は、e-mailか何かでジョブ準備完了を通知させることもできます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Amazon;
using Amazon.Runtime;
using Amazon.Glacier;
using Amazon.Glacier.Model;
using Amazon.SimpleNotificationService;


namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            //設定
            string vaultName = "*** Provide vault name ***";
            string accessKey = "*** Provide Access Key ***";
            string secretKey = "*** Provide Secret Key ***";
            string snsTopic = "*** Provide Amazon SNS topic ***";
            string savePath = "*** Provide File Path ***";
            RegionEndpoint region = RegionEndpoint.APNortheast1;//東京

            //JobIDの取得
            string jobId = GetJobID(vaultName, snsTopic, accessKey, secretKey, region);
            Console.WriteLine("jobId:");
            Console.WriteLine(jobId);

            //job実行準備が完了するまで待機。
            //5時間待つ。又は、snsが届いてから、GetArchiveIDを呼び出す。
            //スマートにやる場合は、AmazoneSQSを使って、数分間隔でjob準備完了状態になるのをポーリングする。
            System.Threading.Thread.Sleep(1000 * 60 * 60 * 5);
            
            //ArchiveIDの取得
            string archiveId = GetArchiveID(vaultName, jobId, savePath, accessKey, secretKey, region);
            Console.WriteLine("archiveId:");
            Console.WriteLine(archiveId);
        }

        private static string GetJobID(string vaultName, string snsTopic, string accessKey, string secretKey, RegionEndpoint region)
        {
            AmazonGlacierClient client = new AmazonGlacierClient(accessKey, secretKey, region);
            AmazonSimpleNotificationServiceClient snsClient = new AmazonSimpleNotificationServiceClient(accessKey, secretKey, region);

            InitiateJobRequest initJobRequest = new InitiateJobRequest()
            {
                VaultName = vaultName,
                JobParameters = new JobParameters()
                {
                    Type = "inventory-retrieval",
                    Description = "This job is to download archive updated as part of getting started",
                    SNSTopic = snsTopic
                }
            };

            InitiateJobResponse initJobResponse = client.InitiateJob(initJobRequest);
            string jobId = initJobResponse.InitiateJobResult.JobId;
            return jobId;
        }

        private static string GetArchiveID(string vaultName, string jobId, string savePath, string accessKey, string secretKey, RegionEndpoint region)
        {
            string archiveId = null;
            AmazonGlacierClient client = new AmazonGlacierClient(accessKey, secretKey, region);
            GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest()
            {
                JobId = jobId,
                VaultName = vaultName
            };
            GetJobOutputResponse getJobOutputResponse = client.GetJobOutput(getJobOutputRequest);
            GetJobOutputResult result = getJobOutputResponse.GetJobOutputResult;

            using (StreamReader sr = new StreamReader(result.Body))
            {
                archiveId = sr.ReadToEnd();
            }
            return archiveId;
        }
    }
}

SDKのサンプルでは、ゴチャゴチャと複雑に書かれていたので、エッセンスだけを抜き出して簡便に書いています。詳細をご覧になりたい方は、Downloading a Vault Inventory in Amazon Glacier Using the AWS SDK for .NETのページにより詳しい使用方法が記載されています。

スマートに書くならば、やはりSDKと同じようにAmazone SQSを利用して、一定間隔でジョブ準備完了に状態が変わることをポーリングするのが良いと思われます。

また、そもそもアーカイブIDを忘れることが悪いので、アップロードと同時にAmazone DynamoDB等にアーカイブIDを記録しておいた方が良いと思われます。