ブロックストレージサービスで車輪の再開発(3)
外部コマンド叩く話のつづき2
さて、今日は _create_qcow2_file() の部分です。
https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nfs.py#L240-L246
qemu-img コマンドを叩かない方法はどうしたらいいんだろう?と思い、とりあえず qemu-img でイメージを生成してみました。すると以下のように一部のヘッダ部分だけ値の入っている 193KB 程度のファイルが生成されます。
$ xxd ~/test.img |grep -v ": 0000 0000 0000 0000 0000 0000 0000 0000 ................"
0000000: 5146 49fb 0000 0003 0000 0000 0000 0000 QFI.............
0000010: 0000 0000 0000 0010 0000 0000 4000 0000 ............@...
0000020: 0000 0000 0000 0002 0000 0000 0003 0000 ................
0000030: 0000 0000 0001 0000 0000 0001 0000 0000 ................
0000060: 0000 0004 0000 0068 0000 0000 0000 0000 .......h........
0010000: 0000 0000 0002 0000 0000 0000 0000 0000 ................
0020000: 0001 0001 0001 0001 0000 0000 0000 0000 ................
で、このヘッダ部分を生成しているのが、Qemu の block/qcow2.c の qcow2_create2() の以下の部分(かな?)と思い、
/* Write the header */
QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header));
header = g_malloc0(cluster_size);
*header = (QCowHeader) {
.magic = cpu_to_be32(QCOW_MAGIC),
.version = cpu_to_be32(version),
.cluster_bits = cpu_to_be32(cluster_bits),
.size = cpu_to_be64(0),
.l1_table_offset = cpu_to_be64(0),
.l1_size = cpu_to_be32(0),
.refcount_table_offset = cpu_to_be64(cluster_size),
.refcount_table_clusters = cpu_to_be32(1),
.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT),
.header_length = cpu_to_be32(sizeof(*header)),
};
if (flags & BLOCK_FLAG_ENCRYPT) {
header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
} else {
header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
}
if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
header->compatible_features |=
cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
}
「じゃぁ、これを Python で書けば」……(ヾノ・∀・`)ナイナイ
書きません。そこまでして「コマンド叩くの好きじゃない」とか言い張るほど強い主張はないです。 っていうことで、コマンド叩く実装のほうがトータルコストが低いなら、コマンドでもいいんじゃないですかね?と思い直しました。1
run_as_root=Trueの謎
1回目のときに「何で run_as_root=True で叩いているんだろう?」って書いちゃったので、全く觝れないわけにはいかないと思い、ちょっぴり觝れます。
とりあえず、Cinder のボリュームが格納されているところを見てみました。
$ LANG=C sudo ls -al /var/lib/cinder/volumes/
total 12
drwxr-xr-x 2 cinder cinder 4096 May 29 2013 .
drwx------ 3 cinder cinder 4096 May 29 2013 ..
-rw-r--r-- 1 cinder cinder 228 Mar 11 22:57 volume-5b519288-53a4-48fc-8ccf-eb5accea7001
うーん、ディレクトリの権限やはり Cinder ユーザの権限で作成できますよね…。わざわざ root で叩く必要性がわからないですが、もっとちゃんと見ていけば理由がわかるかもしれませんが、そこまで OpenStack のコードを追いたくないので諦めます。
どんな機能にするかの話
やっと本題です。もうサクっと作ってしまおうかと思い、とりあえず機能をザックリと決めたいと思います。
まず最初に最低限実装しておきたい機能は以下です。なお、今後実装する段階で、削ったり盛ったりします。(行き当たりばったりなのでσ^^:)
- ボリュームの一覧 – 現在作成されているボリュームの一覧を表示する機能
- インプット: ボリューム ID(任意)
- アウトプット: ボリューム ID、ボリュームサイズ、ボリューム作成日、NFS の共有パス
- ボリュームの作成 – ボリュームを作成する機能
- インプット: ボリュームのサイズ(必須)、ボリュームの名称(必須)、NFS のオプション(任意)
- アウトプット: ボリューム作成の成否、ボリューム ID、ボリュームのサイズ、ボリュームの作成日、NFSの共有パス
- ボリュームの削除
- インプット: ボリューム ID(必須)
- アウトプット: ボリュームの削除の成否
なお、上記の3機能のそれぞれの処理概要は以下になります。
ボリュームの一覧
- インプットでボリューム ID が指定されていれば該当するボリュームを表示し、指定されていなければ全てのボリュームを表示
ボリュームの作成
- インプットに指定されたボリュームの名称が存在すれば既に同じ名前のボリュームが存在する旨を返答し終了
- インプットに指定されたボリュームのサイズでスパースファイルを作成
- 作成したボリュームファイルを何らかのファイルシステムでフォーマット(ファイルシステムは後で検討する)
- ボリュームファイルをマウント
- /etc/exports を変更し、exportfs を叩いて変更を反映させる
- NFSの共有パスなどのボリュームに対する情報をアウトプット
ボリュームの削除
- インプットに指定されたボリュームの ID が無ければエラーをアウトプット
- 当該ボリュームに該当する設定を /etc/exports から削除し、exportfs を叩いて変更を反映させる
- ボリュームファイルをアンマウント
- ボリュームファイルを削除
こんなザックリした感じで進めていこうと思います。今日はこれまで。明日から少しづつ実装していくお話。ちなみに言語はまだ決めてません。
- ただし、lvm コマンドをバシバシ叩きまくるのはイケてないです。そんなに lvm は叩かれることを想定してないと思うので…’ [return]