2011年8月10日水曜日

S3ってなんじゃ?(バージョン管理編)

今回は、S3のバージョン管理機能について触れます。S3ではデフォルトではバージョン機能は無効になっていますが、バケットごとにバージョン管理を有効にすることができます。
AWS SDK for Rubyを利用して、その動作を簡単に見てみましょう。

あらかじめ認証情報設定用のファイルを用意しておきます。
$ vi config.rb
require 'rubygems'
require 'aws'

AWS.config({
:access_key_id => 'アクセスキー',
:secret_access_key => 'シークレットキー'
})

指定されたバケットのファイルとバージョンの全状態を確認するスクリプトを作ります。
$ vi check_version.rb
# 設定情報を読み込む
require File.expand_path(File.dirname(__FILE__) + '/config')

# 引数からバケット名を読み込む
bucket_name = ARGV[0]
unless bucket_name
  puts "Usage: check_version.rb <BUCKET_NAME>"
  exit 1
end

# S3インスタンスの取得
s3 = AWS::S3.new
# バケットオブジェクトの取得
bucket = s3.buckets[bucket_name]
# バケットのバージョンが有効かどうかを出力
puts "state :" + bucket.versioning_state.to_s
# バケットの全バージョン情報を取得
versions = bucket.versions
# 全てのバージョン情報を出力
versions.each(){|obj_ver|
  puts "key=" + obj_ver.object.key + "; version_id=" + obj_ver.version_id + ";"
}

これを実行して全バージョンの情報を確認してみます。
$ ruby check_version.rb hoge-bucket

state :unversioned
key=_1308236999981.png; version_id=null;
key=welcome.txt; version_id=null;

ここで、stateがunversionedとなっているのはバケットがデフォルトでバージョニング無効になっているためです。元々アップされていた_1308236999981.pngとwelcome.txtの2つのファイルのversion_idもnullになっています。

次に、このバケットをバージョニング有効にするためのスクリプトを書きます。
$ vi enable_version.rb
# 設定情報を読み込む
require File.expand_path(File.dirname(__FILE__) + '/config')

# 引数からバケット名を読み込む
bucket_name = ARGV[0]
unless bucket_name
  puts "Usage: check_version.rb <BUCKET_NAME>"
  exit 1
end

# S3インスタンスの取得
s3 = AWS::S3.new
# バージョニングの有効化
s3.buckets[bucket_name].enable_versioning

これを実行して、再度バージョニング状態を確認します。
$ ruby enable_version.rb hoge-bucket
$ ruby check_version.rb hoge-bucket

state :enabled
key=_1308236999981.png; version_id=null;
key=welcome.txt; version_id=null;

state: enabledとなっており、バージョニングが有効になっていることが確認できます。

次に、ファイルをアップロードするスクリプトを作ります。
$ vi upload.rb
# 設定情報を読み込む
require File.expand_path(File.dirname(__FILE__) + '/config')

# 引数からバケット名、ファイル名を読み込む
(bucket_name, file_name) = ARGV
unless bucket_name && file_name
  puts "Usage: upload.rb <BUCKET_NAME> <FILE_NAME>"
  exit 1
end

# S3インスタンスの取得
s3 = AWS::S3.new

# バケットがなければ作成する
b = s3.buckets[bucket_name]
unless b.exists?
  b = s3.buckets.create(bucket_name)
end

# アップロード
basename = File.basename(file_name)
o = b.objects[basename]
o.write(:file => file_name)


このアップロードスクリプトを使用して、バージョニング有効になった状態のバケットに、連続して違う内容のwelcome.txtをアップロードしてみます。
$ echo "hoge" > welcome.txt
$ ruby upload.rb hoge-bucket welcome.txt
$ echo "moge" > welcome.txt
$ ruby upload.rb hoge-bucket welcome.txt

ここで、再度バージョン情報を確認します。
$ ruby check_version.rb hoge-bucket

state : enabled
key=_1308236999981.png; version_id=null;
key=welcome.txt; version_id=1ut2HAksA7WCEkbdlDD3rnBC_OxP8Lvf;
key=welcome.txt; version_id=VpCOAn8Et9ZbOQyk_bKVJGeYaYp2x2W_;
key=welcome.txt; version_id=null;

このように、version_idがついたwelcome.txtが2つ増えていることが確認できます。
ここで、バージョンを指定してファイルを読み込むスクリプトを作成します。
$ vi read_by_version.rb
# 設定情報を読み込む
require File.expand_path(File.dirname(__FILE__) + '/config')

# 引数からバケット名、ファイル名、バージョンIDを読み込む
(bucket_name, file_name, version_id) = ARGV
unless bucket_name && file_name && version_id
  puts "Usage: version_check.rb <BUCKET_NAME>"
  exit 1
end

# S3インスタンスの作成
s3 = AWS::S3.new

# バージョンを指定して読み込んだものを出力
bucket = s3.buckets[bucket_name]
puts bucket.objects[file_name].read({:version_id=>version_id}).to_s

これを先ほどの出力で確認したバージョンIDを指定して個別に実行すると、以下のようにそれぞれのバージョンのファイルの内容を確認することができます。
$ ruby read_by_version.rb hoge-bucket welcome.txt 1ut2HAksA7WCEkbdlDD3rnBC_OxP8Lvf
> moge
$ ruby read_by_version.rb hoge-bucket welcome.txt VpCOAn8Et9ZbOQyk_bKVJGeYaYp2x2W_
> hoge  

このように、S3を使用してバージョン管理ができることを確認できました。
ちなみに、このバージョン機能は、ファイル単位でのバージョン機能のようです。

本日はここまで。