はじめに
KVM環境でポートフォワードを行おうと思って調べてみたところ、どうもlibvirtのフックの仕組みを利用してiptablesを実行するのがよいらしい。 そのフックの概要を忘れないうちに残しておく。
フックのスクリプト
フックはスクリプトとして実装する。 言語はbashやPythonなど、何でもよい。 機能別に呼び出されるスクリプトが分かれており、スクリプトのファイル名は固定である。
スクリプトファイル | 対応する機能 |
---|---|
/etc/libvirt/hooks/daemon | libvirtデーモン |
/etc/libvirt/hooks/qemu | QEMUのゲストであり、KVMの普通のVM |
/etc/libvirt/hooks/lxc | LXCコンテナ |
/etc/libvirt/hooks/libxl | XenのVM |
/etc/libvirt/hooks/network | ネットワーク |
フックの呼び出しのタイミング
各対象の起動や停止などのライフサイクルの変化が発生した場合に呼び出される。 具体的なライフサイクルについては、各フックの仕様を参照。
フックのパラメータ
フックには、次のパラメータが渡される。
引数 | 内容 | 具体値 |
---|---|---|
第1引数 | object | VM名, ネットワーク名, など |
第2引数 | operation | "started", "stopped", など |
第3引数 | sub-operation | "begin", "end", など |
第4引数 | extra argument | "SIGHUP", など |
各引数について、「値なし」の場合は"-"
が引き渡される。
具体的な値の種類と組み合わせは、各フックの仕様を参照。
第1引数objectの詳細情報
第1引数objectの詳細情報は、標準入力からXML形式で取得できる。 例えば、/etc/libvirt/hooks/networkには以下のようなXMLが引き渡されてきた。
<hookData> <network> <name>default</name> <uuid>2cc82eef-28f4-463f-9324-a0f0f3d0578c</uuid> <forward mode='nat'/> <bridge name='virbr0' stp='on' delay='0'/> <mac address='52:54:00:3e:72:43'/> <ip address='192.168.8.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.8.128' end='192.168.8.254'/> </dhcp> </ip> </network> </hookData>
フックの戻り値
フックのスクリプトが戻り値として0を返却すると成功、0以外を返却すると失敗と判定される。
ログ出力
フックのスクリプト内で標準エラーに出力した内容は、ログファイルに記録される。
実験
フックの挙動を確認するため、引数と標準入力をダンプするスクリプトを作成してみた。 どのフックも処理内容は同じなので、スクリプトはひとつだけ作成して、シンボリックリンクを張ることにした。
フックのスクリプトの実体は/etc/libvirt/hooks/hook-logger.py
とし、次の内容で作成。
#!/usr/bin/python3 import datetime import fcntl import os import os.path import sys logfile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "log.txt") with open(logfile, "a+") as f: fcntl.flock(f, fcntl.LOCK_EX) try: f.write(str(datetime.datetime.today()) + " " + str(sys.argv) + "\n") cr = True for line in sys.stdin: cr = line.endswith("\n") f.write(line) if not cr: f.write("\n") finally: fcntl.flock(f, fcntl.LOCK_UN)
このスクリプトに実行権限を付与して、各フックとしてシンボリックリンクを作成する。
$ sudo chmod a+x hook-logger.py $ sudo ln -s hook-logger.py daemon $ sudo ln -s hook-logger.py qemu $ sudo ln -s hook-logger.py lxc $ sudo ln -s hook-logger.py libxl $ sudo ln -s hook-logger.py network
各対象のライフサイクルに変化があると、ファイル/etc/libvirt/hooks/log.txt
に、例えば次のような情報が出力される。
2019-02-17 05:15:12.414193 ['/etc/libvirt/hooks/daemon', '-', 'shutdown', '-', 'shutdown'] 2019-02-17 05:16:01.398895 ['/etc/libvirt/hooks/daemon', '-', 'start', '-', 'start'] 2019-02-17 05:16:04.189531 ['/etc/libvirt/hooks/network', 'default', 'start', 'begin', '-'] <hookData> <network> <name>default</name> (略) 2019-02-17 05:16:05.459755 ['/etc/libvirt/hooks/network', 'default', 'started', 'begin', '-'] <hookData> <network> <name>default</name> (略) 2019-02-17 05:34:23.456336 ['/etc/libvirt/hooks/qemu', 'my-vm', 'prepare', 'begin', '-'] <domain type='kvm' id='2'> <name>my-vm</name> <uuid>8fee996e-99c0-4334-97be-07abe2d9e089</uuid> (略) 2019-02-17 05:34:23.919914 ['/etc/libvirt/hooks/network', 'default', 'plugged', 'begin', '-'] <hookData> <interface type='network'> <mac address='52:54:00:a0:91:82'/> (略)
参考
- Hooks for specific system management