[kupfer: 1/3] virtualbox: update plugin; support vbox4



commit e2441ab787d5b6a8b8701cb62894e6abaa836cba
Author: Karol BÄ?dkowski <karol bedkowski gmail com>
Date:   Thu Jan 20 17:09:57 2011 +0100

    virtualbox: update plugin; support vbox4
    
    + support virtualbox 4 api
    + new options "Force use cli interface".
      Configuration option - allow to force use cli interface for access to
      virtual machines even vboxapi is available.
      This should be useful for some broken system or future version of
      VirtualBox.
    + more logging/debug messages
    + catch exception when closing vboxapi sessions
    + fix problems with incorrect handling "saved" state of vm

 kupfer/plugin/virtualbox/__init__.py         |   49 +++++++--
 kupfer/plugin/virtualbox/constants.py        |    3 +-
 kupfer/plugin/virtualbox/ose_support.py      |   20 +---
 kupfer/plugin/virtualbox/vboxapi4_support.py |  154 ++++++++++++++++++++++++++
 kupfer/plugin/virtualbox/vboxapi_support.py  |   83 ++++++++------
 5 files changed, 248 insertions(+), 61 deletions(-)
---
diff --git a/kupfer/plugin/virtualbox/__init__.py b/kupfer/plugin/virtualbox/__init__.py
index 75a503a..16c1e2f 100644
--- a/kupfer/plugin/virtualbox/__init__.py
+++ b/kupfer/plugin/virtualbox/__init__.py
@@ -8,19 +8,46 @@ __version__ = "0.3"
 __author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
 
 from kupfer.objects import Leaf, Action, Source
-from kupfer import pretty, plugin_support
+from kupfer import pretty
+from kupfer import plugin_support
 from kupfer.obj.apps import ApplicationSource
 
 try:
-	from kupfer.plugin.virtualbox import vboxapi_support as vbox_support
-	pretty.print_info(__name__, 'Using vboxapi...')
+	try:
+		from kupfer.plugin.virtualbox import vboxapi4_support as vboxapi_support
+		pretty.print_info(__name__, 'Using vboxapi4...')
+	except ImportError, err:
+		from kupfer.plugin.virtualbox import vboxapi_support
+		pretty.print_info(__name__, 'Using vboxapi...')
 except ImportError, err:
-	from kupfer.plugin.virtualbox import ose_support as vbox_support
-	pretty.print_info(__name__, 'Using cli...', err)
+	pretty.print_info(__name__, 'vboxapi not available...', err)
+	vboxapi_support = None
 
+from kupfer.plugin.virtualbox import ose_support
 from kupfer.plugin.virtualbox import constants as vbox_const
 
 
+__kupfer_settings__ = plugin_support.PluginSettings(
+	{
+		"key": "force_cli",
+		"label": _("Force use CLI interface"),
+		"type": bool,
+		"value": False,
+	},
+)
+
+
+class _VBoxSupportProxy:
+	def __getattr__(self, attr):
+		vbox = ose_support
+		if vboxapi_support and not __kupfer_settings__['force_cli']:
+			vbox = vboxapi_support
+		return getattr(vbox, attr)
+
+
+vbox_support = _VBoxSupportProxy()
+
+
 class VirtualMachine(Leaf):
 	def __init__(self, obj, name, description):
 		Leaf.__init__(self, obj, name)
@@ -43,9 +70,14 @@ class VirtualMachine(Leaf):
 			yield VMAction(_('Send Power Off Signal'), 'system-shutdown',
 					vbox_const.VM_ACPI_POWEROFF, -5)
 			yield VMAction(_('Pause'), 'pause', vbox_const.VM_PAUSE)
-			yield VMAction(_('Reboot'), 'system-reboot', 
+			yield VMAction(_('Reboot'), 'system-reboot',
 					vbox_const.VM_REBOOT, -10)
-		else: # VM_STATE_PAUSED
+		elif state == vbox_const.VM_STATE_SAVED:
+			yield VMAction(_('Power On'), 'system-run',
+					vbox_const.VM_START_NORMAL)
+			yield VMAction(_('Power On Headless'), 'system-run',
+					vbox_const.VM_START_HEADLESS, -5)
+		else:  # VM_STATE_PAUSED
 			yield VMAction(_('Resume'), 'resume', vbox_const.VM_RESUME)
 
 		if state in (vbox_const.VM_STATE_POWERON, vbox_const.VM_STATE_PAUSED):
@@ -98,6 +130,3 @@ class VBoxMachinesSource(ApplicationSource):
 
 	def provides(self):
 		yield VirtualMachine
-
-
-
diff --git a/kupfer/plugin/virtualbox/constants.py b/kupfer/plugin/virtualbox/constants.py
index 5f85c6b..b32cc4d 100644
--- a/kupfer/plugin/virtualbox/constants.py
+++ b/kupfer/plugin/virtualbox/constants.py
@@ -11,6 +11,7 @@ __version__ = '0.3'
 VM_STATE_POWEROFF = 0
 VM_STATE_POWERON = 1
 VM_STATE_PAUSED = 2
+VM_STATE_SAVED = 3
 
 # virtual machine actions
 VM_START_NORMAL = 1
@@ -21,5 +22,3 @@ VM_ACPI_POWEROFF = 5
 VM_REBOOT = 6
 VM_RESUME = 7
 VM_SAVE = 8
-
-
diff --git a/kupfer/plugin/virtualbox/ose_support.py b/kupfer/plugin/virtualbox/ose_support.py
index 2c74658..cdaf696 100644
--- a/kupfer/plugin/virtualbox/ose_support.py
+++ b/kupfer/plugin/virtualbox/ose_support.py
@@ -31,7 +31,7 @@ _ACTIONS = {
 		vbox_const.VM_PAUSE: 'pause',
 		vbox_const.VM_REBOOT: 'reset',
 		vbox_const.VM_RESUME: 'resume',
-		vbox_const.VM_SAVE: 'savestate'
+		vbox_const.VM_SAVE: 'savestate',
 }
 
 
@@ -50,7 +50,8 @@ def get_machine_state(vm_uuid):
 			state = vbox_const.VM_STATE_PAUSED
 		elif str_state == 'running':
 			state = vbox_const.VM_STATE_POWERON
-
+		elif str_state == 'saved':
+			state = vbox_const.VM_STATE_SAVED
 	except IOError, err:
 		pretty.print_error(__name__, 'get_machine_state', vm_uuid, 'error', err)
 		state = vbox_const.VM_STATE_POWEROFF
@@ -76,7 +77,7 @@ def vm_action(action, vm_uuid):
 
 
 def _get_virtual_machines(config_file):
-	''' load (virtual machine uuid, path to vm config) from virtualbox 
+	''' load (virtual machine uuid, path to vm config) from virtualbox
 		configuration.
 		@param config_file - path to VirtualBox.xml file
 	'''
@@ -84,11 +85,10 @@ def _get_virtual_machines(config_file):
 		dtree = minidom.parse(config_file)
 		machine_registry = dtree.getElementsByTagName('MachineRegistry')[0]
 		for machine in machine_registry.getElementsByTagName('MachineEntry'):
-			yield (machine.getAttribute('uuid')[1:-1], 
+			yield (machine.getAttribute('uuid')[1:-1],
 					machine.getAttribute('src'))
-
 	except StandardError, err:
-		pretty.print_error(__name__, '_get_virtual_machines', config_file, 
+		pretty.print_error(__name__, '_get_virtual_machines', config_file,
 				'error', err)
 
 
@@ -103,23 +103,18 @@ def _get_machine_info(vm_uuid, config_file):
 	try:
 		dtree = minidom.parse(config_file)
 		machine_registry = dtree.getElementsByTagName('Machine')[0]
-
 		os_type = machine_registry.getAttribute('OSType')
 		name = machine_registry.getAttribute('name')
-
 		description = None
 		for machine_registry_child in machine_registry.childNodes:
 			if machine_registry_child.nodeName == 'Description':
 				if machine_registry_child.hasChildNodes():
 					description = machine_registry_child.firstChild.nodeValue
 				break
-
 		return (name, description or os_type)
-
 	except StandardError, err:
 		pretty.print_error(__name__, '_get_machine_info', vm_uuid, 'error' + \
 				config_file, err)
-
 	return None, None
 
 
@@ -131,6 +126,3 @@ def get_machines():
 			name, description = _get_machine_info(vm_uuid, config)
 			if name:
 				yield (vm_uuid, name, description)
-
-
-
diff --git a/kupfer/plugin/virtualbox/vboxapi4_support.py b/kupfer/plugin/virtualbox/vboxapi4_support.py
new file mode 100644
index 0000000..85c4a92
--- /dev/null
+++ b/kupfer/plugin/virtualbox/vboxapi4_support.py
@@ -0,0 +1,154 @@
+# -*- coding: UTF-8 -*-
+'''
+virtualbox_vboxapi_support.py
+
+Control VirtualBox via Python interface (vboxapi).
+Only (?) Sun VirtualBox (no OSE).
+'''
+__author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
+__version__ = "0.3"
+
+from kupfer import pretty
+
+#raise ImportError()
+
+import vboxapi
+
+# check api
+try:
+	vboxapi.VirtualBoxReflectionInfo(None).SessionState_Locked
+except AttributeError:
+	raise ImportError()
+
+from kupfer.plugin.virtualbox import constants as vbox_const
+
+MONITORED_DIRS = None
+IS_DYNAMIC = False
+ICON = "VBox"
+APP_ID = "virtualbox"
+
+
+_ACTIONS = {
+		vbox_const.VM_POWEROFF: lambda c: c.powerDown(),
+		vbox_const.VM_ACPI_POWEROFF: lambda c: c.powerButton(),
+		vbox_const.VM_PAUSE: lambda c: c.pause(),
+		vbox_const.VM_REBOOT: lambda c: c.reset(),
+		vbox_const.VM_RESUME: lambda c: c.resume(),
+		vbox_const.VM_SAVE: lambda c: c.saveState(),
+}
+
+
+def _get_object_session():
+	''' get new session to vm '''
+	vbox, session = None, None
+	try:
+		vbox = vboxapi.VirtualBoxManager(None, None)
+		session = vbox.mgr.getSessionObject(vbox.vbox)
+	except Exception, err:
+		pretty.print_error(__name__, 'virtualbox: get session error ', err)
+	return vbox, session
+
+
+def _get_existing_session(vm_uuid):
+	''' get existing session by machine uuid '''
+	vbox, session = None, None
+	try:
+		vbox = vboxapi.VirtualBoxManager(None, None)
+		session = vbox.mgr.getSessionObject(vbox.vbox)
+	except Exception, err:
+		pretty.print_error(__name__, 'virtualbox: get session error', vm_uuid,
+				err)
+	return vbox, session
+
+
+def get_machine_by_id(vbox, mid):
+	try:
+		mach = vbox.getMachine(mid)
+	except:
+		mach = vbox.findMachine(mid)
+	return mach
+
+
+def get_machine_state(machine_id):
+	''' check vms state (on/off/paused) '''
+	vbox, vbox_sess = _get_object_session()
+	if vbox_sess is None:
+		return vbox_const.VM_STATE_POWEROFF
+	state = vbox_const.VM_STATE_POWERON
+	try:
+		machine = get_machine_by_id(vbox.vbox, machine_id)
+		machine_state = machine.state
+		if machine_state == vbox.constants.MachineState_Paused:
+			state = vbox_const.VM_STATE_PAUSED
+		elif machine_state in (vbox.constants.MachineState_PoweredOff,
+				vbox.constants.MachineState_Aborted,
+				vbox.constants.MachineState_Starting):
+			state = vbox_const.VM_STATE_POWEROFF
+		elif machine_state == vbox.constants.MachineState_Saved:
+			state = vbox_const.VM_STATE_SAVED
+	except Exception, err:  # exception == machine is off (xpcom.Exception)
+		pretty.print_debug(__name__, 'get_machine_state', machine_state, err)
+		# silently set state to off
+		state = vbox_const.VM_STATE_POWEROFF
+	return state
+
+
+def _machine_start(vm_uuid, mode):
+	''' Start virtual machine
+		@param vm_uuid - uuid of virtual machine
+		@param mode - mode: gui, headless
+	'''
+	vbox, session = _get_object_session()
+	if session:
+		try:
+			mach = get_machine_by_id(vbox.vbox, vm_uuid)
+			remote_sess = mach.launchVMProcess(session, mode, '')
+			remote_sess.waitForCompletion(-1)
+			session.unlockMachine()
+		except Exception, err:
+			pretty.print_error(__name__, "StartVM:", vm_uuid, "Mode ", mode,
+					"error", err)
+
+
+def _execute_machine_action(vm_uuid, action):
+	''' Start virtual machine
+		@param vm_uuid - uuid of virtual machine
+		@param action - function called on vbox session
+	'''
+	vbox, session = _get_existing_session(vm_uuid)
+	try:
+		mach = get_machine_by_id(vbox.vbox, vm_uuid)
+		mach.lockMachine(session, vbox.constants.LockType_Shared)
+		action(session.console)
+		session.unlockMachine()
+	except Exception, err:
+		pretty.print_error(__name__, "_execute_machine_action:", repr(action),
+				" vm:", vm_uuid, "error", err)
+
+
+def vm_action(action, vm_uuid):
+	''' change state of the virtual machine
+		@param action - one of the const VM_*
+		@param vm_uuid - virtual machine uuid
+	'''
+	if action == vbox_const.VM_START_NORMAL:
+		_machine_start(vm_uuid, 'gui')
+	elif action == vbox_const.VM_START_HEADLESS:
+		_machine_start(vm_uuid, 'headless')
+	else:
+		command = _ACTIONS[action]
+		_execute_machine_action(vm_uuid, command)
+
+
+def get_machines():
+	''' Get generator of items:
+		(machine uuid, machine name, machine description)
+	'''
+	vbox, vbox_sess = _get_object_session()
+	if vbox_sess is None:
+		return
+
+	machines = vbox.getArray(vbox.vbox, 'machines')
+	for machine in machines:
+		description = machine.description or machine.OSTypeId
+		yield (machine.id, machine.name, description)
diff --git a/kupfer/plugin/virtualbox/vboxapi_support.py b/kupfer/plugin/virtualbox/vboxapi_support.py
index c9f8d63..abea025 100644
--- a/kupfer/plugin/virtualbox/vboxapi_support.py
+++ b/kupfer/plugin/virtualbox/vboxapi_support.py
@@ -6,9 +6,9 @@ Control VirtualBox via Python interface (vboxapi).
 Only (?) Sun VirtualBox (no OSE).
 '''
 __author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
-__version__ = "0.3"
+__version__ = "2011-01-20"
 
-from kupfer import pretty 
+from kupfer import pretty
 
 #raise ImportError()
 
@@ -21,30 +21,32 @@ IS_DYNAMIC = False
 ICON = "VBox"
 APP_ID = "virtualbox"
 
-
 _ACTIONS = {
-		vbox_const.VM_POWEROFF:			lambda c:c.powerDown(),
-		vbox_const.VM_ACPI_POWEROFF:	lambda c:c.powerButton(),
-		vbox_const.VM_PAUSE:			lambda c:c.pause(),
-		vbox_const.VM_REBOOT:			lambda c:c.reset(),
-		vbox_const.VM_RESUME:			lambda c:c.resume(),
-		vbox_const.VM_SAVE:				lambda c:c.saveState()
+		vbox_const.VM_POWEROFF: lambda c: c.powerDown(),
+		vbox_const.VM_ACPI_POWEROFF: lambda c: c.powerButton(),
+		vbox_const.VM_PAUSE: lambda c: c.pause(),
+		vbox_const.VM_REBOOT: lambda c: c.reset(),
+		vbox_const.VM_RESUME: lambda c: c.resume(),
+		vbox_const.VM_SAVE: lambda c: c.saveState(),
 }
 
 
 def _get_object_session():
 	''' get new session to vm '''
+	pretty.print_debug(__name__, '_get_object_session start')
 	vbox, session = None, None
 	try:
 		vbox = vboxapi.VirtualBoxManager(None, None)
 		session = vbox.mgr.getSessionObject(vbox.vbox)
 	except Exception, err:
 		pretty.print_error(__name__, 'virtualbox: get session error ', err)
-
+	pretty.print_debug(__name__, '_get_object_session finished', vbox, session)
 	return vbox, session
 
+
 def _get_existing_session(vm_uuid):
 	''' get existing session by machine uuid '''
+	pretty.print_debug(__name__, '_get_existing_session start')
 	vbox, session = None, None
 	try:
 		vbox = vboxapi.VirtualBoxManager(None, None)
@@ -53,73 +55,82 @@ def _get_existing_session(vm_uuid):
 	except Exception, err:
 		pretty.print_error(__name__, 'virtualbox: get session error', vm_uuid,
 				err)
-
+	pretty.print_debug(__name__, '_get_existing_session finished', vbox, session)
 	return vbox, session
 
+
 def get_machine_state(machine_id):
 	''' check vms state (on/off/paused) '''
-	
+	pretty.print_debug(__name__, 'get_machine_state', machine_id)
 	vbox, vbox_sess = _get_object_session()
 	if vbox_sess is None:
 		return vbox_const.VM_STATE_POWEROFF
-
 	state = vbox_const.VM_STATE_POWERON
 	try:
 		vbox.vbox.openExistingSession(vbox_sess, machine_id)
 		machine_state = vbox_sess.machine.state
 		if machine_state == vbox.constants.MachineState_Paused:
 			state = vbox_const.VM_STATE_PAUSED
-		elif machine_state in (vbox.constants.MachineState_PoweredOff, 
+		elif machine_state in (vbox.constants.MachineState_PoweredOff,
 				vbox.constants.MachineState_Aborted,
 				vbox.constants.MachineState_Starting):
 			state = vbox_const.VM_STATE_POWEROFF
-	except Exception: # exception == machine is off (xpcom.Exception)
+		elif machine_state == vbox.constants.MachineState_Saved:
+			state = vbox_const.VM_STATE_SAVED
+	except Exception:  # exception == machine is off (xpcom.Exception)
 		# silently set state to off
 		state = vbox_const.VM_STATE_POWEROFF
-
-	if vbox_sess.state == vbox.constants.SessionState_Open:
-		vbox_sess.close()
-
+		pretty.print_debug(__name__, 'get_machine_state error', err)
+	try:
+		if vbox_sess.state == vbox.constants.SessionState_Open:
+			vbox_sess.close()
+	except Exception:  # varoius errors (xpcom.Exception)
+		pass
+	pretty.print_debug(__name__, 'get_machine_state finish', machine_id, state)
 	return state
 
 
 def _machine_start(vm_uuid, mode):
-	''' Start virtual machine 
+	''' Start virtual machine
 		@param vm_uuid - uuid of virtual machine
 		@param mode - mode: gui, headless
 	'''
 	vbox, session = _get_object_session()
 	if session:
 		try:
-			remote_sess = vbox.vbox.openRemoteSession(session, vm_uuid, mode, 
+			remote_sess = vbox.vbox.openRemoteSession(session, vm_uuid, mode,
 					'')
 			remote_sess.waitForCompletion(-1)
-		except Exception, err: 
-			pretty.print_error(__name__, "StartVM:", vm_uuid, "Mode ", mode, 
+		except Exception, err:
+			pretty.print_error(__name__, "StartVM:", vm_uuid, "Mode ", mode,
 					"error", err)
-
-		if session.state == vbox.constants.SessionState_Open:
-			session.close()
+		try:
+			if session.state == vbox.constants.SessionState_Open:
+				session.close()
+		except Exception:  # varoius errors (xpcom.Exception)
+			pass
 
 
 def _execute_machine_action(vm_uuid, action):
-	''' Start virtual machine 
+	''' Start virtual machine
 		@param vm_uuid - uuid of virtual machine
 		@param action - function called on vbox session
 	'''
 	vbox, session = _get_existing_session(vm_uuid)
 	try:
 		action(session.console)
-	except Exception, err: 
+	except Exception, err:
 		pretty.print_error(__name__, "_execute_machine_action:", repr(action),
 				" vm:", vm_uuid, "error", err)
-
-	if session.state == vbox.constants.SessionState_Open:
-		session.close()
+	try:
+		if session.state == vbox.constants.SessionState_Open:
+			session.close()
+	except Exception:  # varoius errors (xpcom.Exception)
+		pass
 
 
 def vm_action(action, vm_uuid):
-	''' change state of the virtual machine 
+	''' change state of the virtual machine
 		@param action - one of the const VM_*
 		@param vm_uuid - virtual machine uuid
 	'''
@@ -133,15 +144,17 @@ def vm_action(action, vm_uuid):
 
 
 def get_machines():
-	''' Get generator of items: 
+	''' Get generator of items:
 		(machine uuid, machine name, machine description)
 	'''
+	pretty.print_debug(__name__, 'get_machines start')
 	vbox, vbox_sess = _get_object_session()
 	if vbox_sess is None:
 		return
-
 	machines = vbox.getArray(vbox.vbox, 'machines')
 	for machine in machines:
+		pretty.print_debug(__name__, 'get_machines; found machine',
+				machine.id, machine.name)
 		description = machine.description or machine.OSTypeId
 		yield (machine.id, machine.name, description)
-
+	pretty.print_debug(__name__, 'get_machines finished')



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]