preload
2月 27

Amazon Web Service の Simple DB を試してみたけど、なかなかリクエストの作成がうまくいかなくて、一回リクエストに成功したところで、明日も早いしもう寝るか、というポスト。へにょいリクエスト作成用の Ruby クラス付き。


Amazon Simple DB (以下、ASDB)
は Web ベースで利用できるデータベースサービス。REST やら SOAP やらでアクセスできる。利用には Amazon Web Service (以下、AWS) のアカウントと Simple DB サービスへのサインアップが必要。2007 年末くらいから公開されていたのだが、サインアップが遅れた (Limited Beta の) ため、順番待ちに入っていた。で、1 月末にようやく使えるようになった。
ちなみに、S3 やら EC2 と同じく従量課金。手軽にスケールアウトできそうな反面、規模によっちゃ実はそんなに安くないんじゃないの?とハマりそうではある。(EC2 立ち上げっぱなしで放置してたら $70/月 くらいかかった。)

ASDB では、Domain というデータセットのハコに Item という単位でレコードを追加していく。Item には Attribute という名前で属性を付加する事ができ、記録されているレコードには Query によりアクセスする事ができる。ちょっと強引に RDB のように解釈するなら、Domain がテーブル、Item がレコード、Attribute はカラムみたいなものだとおもう。

まず、REST の API を使って、上記でいう Domain を定義する CreateDomain アクションを試してみる。実際の利用には、AWS にサインアップして得られる AWS Access Key ID と AWS Secret Access Key が必要。

ASDB へのリクエストの構成要素は大まかに以下のような感じ。これを GET のパラメタに含める。

  • AWS Access Key ID
  • アクション
  • アクション毎に指定するオプションパラメタ
  • タイムスタンプ
  • APIバージョン
  • シグネチャバージョン
  • シグネチャ

ここで、最後のシグネチャは、以下のようにして作る。

  1. シグネチャ以外の構成要素 (AWS Access Key ID 〜 API バージョン) をキー名で昇順ソートする
  2. ソートしたペアのキーと値をセパレータとか付けずに単純に並べる
  3. 並べたパラメタを HMAC-SHA-1 にかけてメッセージダイジェストを得る。この時の秘密鍵に AWS Secret Access Key を指定する
  4. 得られたダイジェストを Base64 エンコードする
  5. 得られたエンコード文字列を更に URL エンコードする

このようにして得られたシグネチャを Signature 値としてリクエストに含める事で、ASDB がメッセージの正当性を確認してくれるというしくみ。

で、このリクエストを作成するクラスが以下のもの (AWSACCESSKEY やら AWSSECRETKEY はサインアップして得られるものを使う):

require 'openssl'
require 'base64'
require 'cgi'
class AmazonSimpleDb
BASEURI = 'https://sdb.amazonaws.com/?'
AWSACCESSKEY = 'Your AWS Access Key'
AWSSECRETKEY = 'Your AWS Secret Key'
def initialize
@params = Hash.new
@params.store('AWSAccessKeyId', AWSACCESSKEY)
@params.store('SignatureVersion', '1')
@params.store('Version', '2007-11-07')
end
def add_param(key, value)
@params.store(key, value)
end
def request_uri
uri = BASEURI
message = ''
(@params.sort_by { |x| x[0].downcase }).each do |e|
uri << "#{CGI.escape(e[0])}=#{CGI.escape(e[1])}&"
message << "#{e[0]}#{e[1]}"
end
hmac = OpenSSL::HMAC.new(AWSSECRETKEY, OpenSSL::Digest::SHA1.new)
hmac.update(message)
signature = CGI.escape(Base64.encode64(hmac.digest).chop)
uri << "Signature=#{signature}"
end
end

sort_by してるんで、Ruby は 1.8 以上で。パラメタは case-sensitive なのに、ソート時は case-insensitive だったり、生メッセージは URL エンコード不要だったり(そりゃそうか)、Base64 したら最後に改行文字が入ってたりにハマった。

これを AmazonSimpleDb.rb とかで保存して、以下のような感じで使う。タイムスタンプで指定してる日付は適当。DomainName に DoCoMo とか指定してるのは、機種情報 DB を作ってみようとしただけで、深い意味は無し。XXX やら YYY はダミーです。

$ irb -r 'AmazonSimpleDb'
irb(main):001:0> asdb = AmazonSimpleDb.new
=> #"2007-11-07", "AWSAccessKeyId"=>"XXXXXXXXXXXXXXXX", "SignatureVersion"=>"1"}>
irb(main):002:0> asdb.add_param('Action', 'CreateDomain')
=> "CreateDomain"
irb(main):003:0> asdb.add_param('DomainName', 'DoCoMo')
=> "DoCoMo"
irb(main):004:0> asdb.add_param('Timestamp', '2008-02-26T23:27:00-09:00')
=> "2008-02-26T23:27:00-09:00"
irb(main):005:0> asdb.request_uri
=> "https://sdb.amazonaws.com/?Action=CreateDomain&
AWSAccessKeyId=XXXXXXXXXXXXXXXX&
DomainName=DoCoMo&
SignatureVersion=1&
Timestamp=2008-02-26T23%3A27%3A00-09%3A00&
Version=2007-11-07&
Signature=YYYYYYYYYYYY" (実際は一行)

得られた request_uri にブラウザとか適当な https が行けるクライアントからリクエストを投げれば XML で結果が返ってくる。net/http でアクセスするところはまだ作ってない。ていうか、まだ PutAttributes も Query も試してないし。これでバッコンバッコンリクエスト投げたらいくら請求くるんだろう。。誰かやってみたひと居ないかな..

参考:



関連していそうなエントリ:

One Response to “Amazon SimpleDB を試してみた”

  1. サイキョウライン » AmazonのAPIが変わる件。 Says:

    [...] から始まって、ググってたどり着いた Amazon SimpleDB を試してみた [...]