vboxapiでVirtualBoxをPythonで操作その2
対象: VirtualBox-3.1, Python-2.6
前回の続きです。
昨日は、VM一覧の取得と簡単な内容表示まで書きました。
machinesというのは、リファレンスでいうところの、IMachineインターフェースを実装したオブジェクトのリストになっています。
import vboxapi vbm = vboxapi.VirtualBoxManager(None, None) vbox = vbm.vbox machines = vbm.getArray(vbox, 'machines') for m in machines: print "uuid =", m.id
IMachineが保持している情報のうち、特に重要なものがid属性です。idには各VMのwikipedia:UUIDを保持しています。これを使ってVirtualBoxに「このVM」を指定する仕様になっています。
VMの状態変更(失敗編)
では早速VMの状態を変更してみましょう。
とはいえ、いきなりVMを起動したりHDDを取り外したりするのはリスキーなので、影響が小さいVRDP機能の有効無効の切り替えから試してみましょう。
念のためテストは壊れてもいいVMで行います。
import vboxapi vbm = vboxapi.VirtualBoxManager(None, None) vbox = vbm.vbox m = vbox.getMachine('4f2f****-...') m.VRDPServer.enabled = not m.VRDPServer.enabled
Traceback (most recent call last): File "<stdin>", line 2, in <module> File "/usr/lib/virtualbox/sdk/bindings/xpcom/python/xpcom/client/__init__.py", line 397, in __setattr__ setattr(interface, attr, val) File "/usr/lib/virtualbox/sdk/bindings/xpcom/python/xpcom/client/__init__.py", line 488, in __setattr__ return XPTC_InvokeByIndex(self._comobj_, method_index, real_param_infos) xpcom.Exception: 0x80bb0002 (The machine is not mutable (state is PoweredOff))
「machineは変更不可能だよ(状態は PoweredOffだよ)」という例外が飛んできました。
原因はVMに対する状態変更操作が競合しないように、状態変更はセッションを開いてから行う仕組みになっているからです。
"state is PoweredOff"は無関係でワナです。私は30分ハマりました。
VMの状態変更(セッション編)
import vboxapi mid = '4f2f****-...' vbm = vboxapi.VirtualBoxManager(None, None) const = vboxapi.VirtualBox_constants.VirtualBoxReflectionInfo(False) vbox = vbm.vbox m = vbox.getMachine(mid) print "BEFORE:", m.VRDPServer.enabled sessionManager = vboxapi.SessionManager(vbm) session = sessionManager.getSessionObject(vbox) # session = vbm.mgr.getSessionObject(vbox) # これでも良い if m.sessionState == const.SessionState_Closed: vbox.openSession(session, mid) elif m.sessionState == const.SessionState_Open: vbox.openExistingSession(session, mid) else: # その他の状態の場合はとりあえず例外 raise Exception() v = session.machine.VRDPServer v.enabled = not v.enabled session.machine.saveSettings() session.close() print "AFTER:", m.VRDPServer.enabled
変更できました。
BEFORE: True AFTER: False
VirtualBoxReflectionInfo
VirtualBoxReflectionInfo には、状態を表す定数などが定義されています。
/usr/share/pyshared/vboxapi/VirtualBox_constants.py
ソースを読むだけで、vboxapiでどのような操作や情報取得ができるのかがわかります。
以下は使用例です。
import vboxapi const = vboxapi.VirtualBox_constants.VirtualBoxReflectionInfo(False) mid = '4f2f****-...' state = vboxapi.VirtualBoxManager(None, None).vbox.getMachine(mid).state print 'state:', state print 'isPoweredOff:', const.MachineState_PoweredOff == state
state: 1 isPoweredOff: True
Sessionの取得
ISessionはSessionManagerから作ります。
作ったISessionはUUIDでVMを指定して開きます。
開くには、VMのsessionStateの状態によってIVirtualBoxのopenSessionとopenExistingSessionを使い分ける必要があります。
sessionManager = vboxapi.SessionManager(vbm) session = sessionManager.getSessionObject(vbox) # session = vbm.mgr.getSessionObject(vbox) # これでも良い if m.sessionState == const.SessionState_Closed: vbox.openSession(session, mid) elif m.sessionState == const.SessionState_Open: vbox.openExistingSession(session, mid)
APIドキュメントには以下のように記述してあります。
SessionState_Open The machine has an open direct session;
私が試した限りでは、VMが起動している場合にはOpenが帰るようですが、他に条件があるのかは不明です。VMを起動するには一度RemoteSessionを開く必要があるので、その関係でしょうか。
vboxshell.pyは、起動している状態でのみ有効な操作をするときにはopenExistingSession決め打ちでした。
sessionを開いてsession.machineからIMachineを取得して操作すれば、例外が出ることなくVMの状態(設定)を変更できました。
machine.saveSettings() をして状態を保存し、session.close()でISessionを閉じましょう。
ここまでのまとめ
- IMachine.idは、VMを一意に特定するIDを返します。
- vbox.getMachineなどで取得できるIMachineオブジェクトは情報の取得にのみ使用できます。
- vboxshell.pyはPython-APIのサンプルに最適です。
- VirtualBox_constants.pyを見てみるとなんとなく全容がわかります。
- VMの状態を変更するにはsessionを作って開いてsession.machineからIMachineを取得して操作します。
今後の予定
VMを起動したり停止したりする。