vboxapiでVirtualBoxをPythonで操作その3
対象: VirtualBox-3.1, Python-2.6
前回、前々回の続きです。
VMを起動したり電源をブチっと切ってみたり、一時停止したりしてみます。これらの操作はIMachineのメソッドでははありません。m.pause() とかできたら簡単そうなのですが。
まず、VMがどのような状態を持つのかを確認しておきましょう。
VMが持つ状態
ドキュメントのenum MachineStateに状態遷移図がありますので、以下に引用します。
(略) +-> PoweredOff --+-->[powerUp()]--> Starting --+ | +-----[resume()]-----+ | | | | V | | Aborted -----+ +--> Running --[pause()]--> Paused | | ^ | ^ | (略)
非常にワクワクする図ですね。
VMの起動
ドキュメント通りにpowerUp()で起動するとなぜか失敗してしまいますので、前回ちらりと書いたように、VMの起動はopenRemoteSessionでRemoteSessionを開く方法を使います。
ドキュメントと違いますが、vboxshell.pyもopenRemoteSessionでやっていますので気にしないようにします。
なお、今回のコードからは状態チェックは省略しています。
import vboxapi mid = '4f2f****-...' vbm = vboxapi.VirtualBoxManager(None, None) vbox = vbm.vbox sessionManager = vboxapi.SessionManager(vbm) session = sessionManager.getSessionObject(vbox) progress = vbox.openRemoteSession(session, mid, "vrdp", "") while not progress.completed: print "p:", progress.percent print "result:", progress.resultCode session.close()
時間がかかる処理はIProgressを返しますので、進捗や残り時間を表示することができます。
p: 0 ...(略) p: 0 p: 100 result: 0
すぐ終了してしまいましたが、起動処理が始まりました。
なお、VMはRunningになりますが、VM上のOSは起動プロセスの真っ最中です。
VMの電源オフ
電源オフは即電源を切ることです。実際のハードウェアで電源ボタンの長押しをした場合や、電源ケーブルを抜いた操作に近いです。
このテストをする前に、動作状態のSnapShotを取っておくことをお勧めします。
import vboxapi mid = '4f2f****-...' vbm = vboxapi.VirtualBoxManager(None, None) vbox = vbm.vbox sessionManager = vboxapi.SessionManager(vbm) session = sessionManager.getSessionObject(vbox) vbox.openExistingSession(session, mid) progress = session.console.powerDown() while not progress.completed: print "p:", progress.percent session.close()
多くの操作は、session.consoleでIConsoleオブジェクトを取得し、そこから操作します。冒頭の失敗するpowerUp()もIConsoleのメソッドです。
実行結果です(途中の行は随時省略)。percentを表示しながら電源が切れました。
p: 28 p: 42 p: 70 p: 84
なお、今時のPCは電源ボタンを押すと、wikipedia:ACPIのPowerOff信号が飛ぶようになっています。そちらの処理をしたい場合は、IConsole.powerButtonを使います。
pause, resume (一時停止、再開)
電源Offとほぼ同じ手順です。一時停止は一瞬で完了するためかIProgressを返しません。
import vboxapi mid = '4f2f****-...' vbm = vboxapi.VirtualBoxManager(None, None) vbox = vbm.vbox sessionManager = vboxapi.SessionManager(vbm) session = sessionManager.getSessionObject(vbox) vbox.openExistingSession(session, mid) session.console.pause() # session.console.resume() # resume()ならresume session.close()
簡単ですね。
マウスやキーボードを制御する
APIからVMのマウスやキーボードを操作できます。
VM上のOSの状態が取れないのが難点ですが、色々な可能性を秘めたAPIです。
このサンプルは、VM上のOSがWindowsで、OS起動が完了しており、デスクトップが表示された状態を想定しています。
スクリプトで、以下の操作をしますので、これらの操作をさせても問題ないか確認してください。
- マウスを画面の左下に移動
- 画面の左下でマウスの左ボタンを押して、放す(スタートメニュー表示)
- キーボードのWin+Eを押して、放す(ファイルエクスプローラの起動)
- Ctrl+Alt+Deleteを押して自動的に放す(タスクマネージャ表示)
import vboxapi mid = '4f2f****-...' vbm = vboxapi.VirtualBoxManager(None, None) vbox = vbm.vbox sessionManager = vboxapi.SessionManager(vbm) session = sessionManager.getSessionObject(vbox) vbox.openExistingSession(session, mid) session.machine.VRDPServer.enabled = True print session.machine.VRDPServer.ports session.machine.saveSettings() console = session.console x = 1 y = console.display.height dz = dw = 0 buttonState = 0b001 # 0b010 : middleButton, 0b100 : rightButton console.mouse.putMouseEventAbsolute(x, y, dz, dw, 0) console.mouse.putMouseEventAbsolute(x, y, dz, dw, buttonState) console.mouse.putMouseEventAbsolute(x, y, dz, dw, 0) pushLeftWin = [0xe0, 0x5b] pushE = [0x12] releaseLeftWin = [0xe0, 0xdb] releaseE = [0x92] console.keyboard.putScancodes(pushLeftWin + pushE) console.keyboard.putScancodes(releaseLeftWin + releaseE) console.keyboard.putCAD() session.close()
ゲストOSがWindowsの方は、スタートメニューが開き、ファイルエクスプローラとタスクマネージャが開いたはずです。(GUIの画面を開いていない方は、途中でVRDPを有効化してポート番号を表示させましたので、そこにRDP接続してください。)
putScancodesで送信しているのは、スキャンコードというものです。
押したときの信号と放したときの信号が別々に定義されています。キーは押したら放しましょう。
putCADでは、一度にCtrl+Alt+Deleteを送信できます。(そして自動的に放すようです)
ここまでのまとめ
- MachineStateの状態遷移図はワクワクします。
- 起動はopenRemoteSessionです。
- IConsole.fooMethod()で状態を変更します。
- 一部の状態変更メソッド呼び出しは、ブロックせず、IProgressを返してすぐに戻ります。
- IConsole.keyboardとIConsole.mouseでマウスとキーボードを操作できます。
今後の予定
サンプルコードはこれで終わりにします。
次回はシリーズ最終回で、調査中に見つけた、vboxapiを利用したアプリやプロジェクトを紹介します。