Move opening of connections into a background thread to avoid locking the UI
This commit is contained in:
parent
99c92b9471
commit
96eb9f5f24
|
@ -26,6 +26,8 @@ from time import time
|
||||||
import logging
|
import logging
|
||||||
from socket import gethostbyaddr, gethostname
|
from socket import gethostbyaddr, gethostname
|
||||||
import dbus
|
import dbus
|
||||||
|
import threading
|
||||||
|
import gtk
|
||||||
|
|
||||||
from virtManager.domain import vmmDomain
|
from virtManager.domain import vmmDomain
|
||||||
from virtManager.network import vmmNetwork
|
from virtManager.network import vmmNetwork
|
||||||
|
@ -96,6 +98,8 @@ class vmmConnection(gobject.GObject):
|
||||||
[]),
|
[]),
|
||||||
"state-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
"state-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||||
[]),
|
[]),
|
||||||
|
"connect-error": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||||
|
[str]),
|
||||||
}
|
}
|
||||||
|
|
||||||
STATE_DISCONNECTED = 0
|
STATE_DISCONNECTED = 0
|
||||||
|
@ -108,6 +112,8 @@ class vmmConnection(gobject.GObject):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.readOnly = readOnly
|
self.readOnly = readOnly
|
||||||
|
|
||||||
|
self.connectThread = None
|
||||||
|
self.connectError = None
|
||||||
self.uri = uri
|
self.uri = uri
|
||||||
if self.uri is None or self.uri.lower() == "xen":
|
if self.uri is None or self.uri.lower() == "xen":
|
||||||
self.uri = "xen:///"
|
self.uri = "xen:///"
|
||||||
|
@ -279,6 +285,15 @@ class vmmConnection(gobject.GObject):
|
||||||
|
|
||||||
self.state = self.STATE_CONNECTING
|
self.state = self.STATE_CONNECTING
|
||||||
self.emit("state-changed")
|
self.emit("state-changed")
|
||||||
|
|
||||||
|
logging.debug("Scheduling background open thread for " + self.uri)
|
||||||
|
self.connectThread = threading.Thread(target = self._open_thread, name="Connect " + self.uri)
|
||||||
|
self.connectThread.setDaemon(True)
|
||||||
|
self.connectThread.start()
|
||||||
|
|
||||||
|
|
||||||
|
def _open_thread(self):
|
||||||
|
logging.debug("Background thread is running")
|
||||||
try:
|
try:
|
||||||
if self.readOnly is None:
|
if self.readOnly is None:
|
||||||
try:
|
try:
|
||||||
|
@ -293,12 +308,42 @@ class vmmConnection(gobject.GObject):
|
||||||
else:
|
else:
|
||||||
self.vmm = libvirt.open(self.uri)
|
self.vmm = libvirt.open(self.uri)
|
||||||
self.state = self.STATE_ACTIVE
|
self.state = self.STATE_ACTIVE
|
||||||
self.tick()
|
|
||||||
self.emit("state-changed")
|
|
||||||
except:
|
except:
|
||||||
self.state = self.STATE_DISCONNECTED
|
self.state = self.STATE_DISCONNECTED
|
||||||
|
|
||||||
|
(type, value, stacktrace) = sys.exc_info ()
|
||||||
|
# Detailed error message, in English so it can be Googled.
|
||||||
|
self.connectError = \
|
||||||
|
("Unable to open connection to hypervisor URI '%s':\n" %
|
||||||
|
str(self.uri)) + \
|
||||||
|
str(type) + " " + str(value) + "\n" + \
|
||||||
|
traceback.format_exc (stacktrace)
|
||||||
|
logging.error(self.connectError)
|
||||||
|
|
||||||
|
# We want to kill off this thread asap, so schedule a gobject
|
||||||
|
# idle even to inform the UI of result
|
||||||
|
logging.debug("Background open thread complete, scheduling notify")
|
||||||
|
gtk.gdk.threads_enter()
|
||||||
|
try:
|
||||||
|
gobject.idle_add(self._open_notify)
|
||||||
|
finally:
|
||||||
|
gtk.gdk.threads_leave()
|
||||||
|
self.connectThread = None
|
||||||
|
|
||||||
|
def _open_notify(self):
|
||||||
|
logging.debug("Notifying open result")
|
||||||
|
gtk.gdk.threads_enter()
|
||||||
|
try:
|
||||||
|
if self.state == self.STATE_ACTIVE:
|
||||||
|
self.tick()
|
||||||
self.emit("state-changed")
|
self.emit("state-changed")
|
||||||
raise
|
|
||||||
|
if self.state == self.STATE_DISCONNECTED:
|
||||||
|
self.emit("connect-error", self.connectError)
|
||||||
|
self.connectError = None
|
||||||
|
finally:
|
||||||
|
gtk.gdk.threads_leave()
|
||||||
|
|
||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
if self.state != self.STATE_ACTIVE:
|
if self.state != self.STATE_ACTIVE:
|
||||||
|
|
|
@ -34,7 +34,6 @@ from virtManager.console import vmmConsole
|
||||||
from virtManager.asyncjob import vmmAsyncJob
|
from virtManager.asyncjob import vmmAsyncJob
|
||||||
from virtManager.create import vmmCreate
|
from virtManager.create import vmmCreate
|
||||||
from virtManager.serialcon import vmmSerialConsole
|
from virtManager.serialcon import vmmSerialConsole
|
||||||
from virtManager.error import vmmErrorDialog
|
|
||||||
from virtManager.host import vmmHost
|
from virtManager.host import vmmHost
|
||||||
|
|
||||||
class vmmEngine(gobject.GObject):
|
class vmmEngine(gobject.GObject):
|
||||||
|
@ -82,43 +81,6 @@ class vmmEngine(gobject.GObject):
|
||||||
self.show_manager()
|
self.show_manager()
|
||||||
return conn
|
return conn
|
||||||
except:
|
except:
|
||||||
(type, value, stacktrace) = sys.exc_info ()
|
|
||||||
|
|
||||||
# Detailed error message, in English so it can be Googled.
|
|
||||||
details = \
|
|
||||||
("Unable to open connection to hypervisor URI '%s':\n" %
|
|
||||||
str(uri)) + \
|
|
||||||
str(type) + " " + str(value) + "\n" + \
|
|
||||||
traceback.format_exc (stacktrace)
|
|
||||||
logging.error (details)
|
|
||||||
|
|
||||||
# Error dialog.
|
|
||||||
if uri is None:
|
|
||||||
uri = "xen"
|
|
||||||
if uri == "xen":
|
|
||||||
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
|
|
||||||
gtk.BUTTONS_CLOSE,
|
|
||||||
_("Unable to open a connection to the Xen hypervisor/daemon.\n\n" +
|
|
||||||
"Verify that:\n" +
|
|
||||||
" - A Xen host kernel was booted\n" +
|
|
||||||
" - The Xen service has been started\n"),
|
|
||||||
details)
|
|
||||||
elif uri.startswith("qemu:"):
|
|
||||||
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
|
|
||||||
gtk.BUTTONS_CLOSE,
|
|
||||||
_("Unable to open a connection to the QEMU management daemon.\n\n" +
|
|
||||||
"Verify that:\n" +
|
|
||||||
" - The 'libvirt_qemud' daemon has been started\n"),
|
|
||||||
details)
|
|
||||||
else:
|
|
||||||
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
|
|
||||||
gtk.BUTTONS_CLOSE,
|
|
||||||
_("Unable to open connection to hypervisor '%s'") % str(uri),
|
|
||||||
details)
|
|
||||||
dg.set_title(_("Virtual Machine Manager Connection Failure"))
|
|
||||||
dg.run()
|
|
||||||
dg.hide()
|
|
||||||
dg.destroy()
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _connect_cancelled(self, connect):
|
def _connect_cancelled(self, connect):
|
||||||
|
|
|
@ -22,13 +22,14 @@ import gtk
|
||||||
import gtk.glade
|
import gtk.glade
|
||||||
import threading
|
import threading
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
import sparkline
|
import sparkline
|
||||||
import libvirt
|
import libvirt
|
||||||
|
|
||||||
from virtManager.connection import vmmConnection
|
from virtManager.connection import vmmConnection
|
||||||
from virtManager.asyncjob import vmmAsyncJob
|
from virtManager.asyncjob import vmmAsyncJob
|
||||||
|
from virtManager.error import vmmErrorDialog
|
||||||
|
|
||||||
VMLIST_SORT_ID = 1
|
VMLIST_SORT_ID = 1
|
||||||
VMLIST_SORT_NAME = 2
|
VMLIST_SORT_NAME = 2
|
||||||
|
@ -503,7 +504,7 @@ class vmmManager(gobject.GObject):
|
||||||
row[ROW_VCPUS] = conn.host_active_processor_count()
|
row[ROW_VCPUS] = conn.host_active_processor_count()
|
||||||
row[ROW_MEM] = conn.pretty_current_memory()
|
row[ROW_MEM] = conn.pretty_current_memory()
|
||||||
row[ROW_MEM_USAGE] = conn.current_memory_percentage()
|
row[ROW_MEM_USAGE] = conn.current_memory_percentage()
|
||||||
if conn.get_state() == vmmConnection.STATE_DISCONNECTED:
|
if conn.get_state() in [vmmConnection.STATE_DISCONNECTED, vmmConnection.STATE_CONNECTING]:
|
||||||
row[ROW_ACTION] = gtk.STOCK_DELETE
|
row[ROW_ACTION] = gtk.STOCK_DELETE
|
||||||
parent = self.rows[conn.get_uri()].iter
|
parent = self.rows[conn.get_uri()].iter
|
||||||
if parent is not None:
|
if parent is not None:
|
||||||
|
@ -942,6 +943,7 @@ class vmmManager(gobject.GObject):
|
||||||
conn.connect("vm-removed", self.vm_removed)
|
conn.connect("vm-removed", self.vm_removed)
|
||||||
conn.connect("resources-sampled", self.conn_refresh_resources)
|
conn.connect("resources-sampled", self.conn_refresh_resources)
|
||||||
conn.connect("state-changed", self.conn_state_changed)
|
conn.connect("state-changed", self.conn_state_changed)
|
||||||
|
conn.connect("connect-error", self._connect_error)
|
||||||
conn.connect("vm-started", self.vm_started)
|
conn.connect("vm-started", self.vm_started)
|
||||||
# add the connection to the treeModel
|
# add the connection to the treeModel
|
||||||
vmlist = self.window.get_widget("vm-list")
|
vmlist = self.window.get_widget("vm-list")
|
||||||
|
@ -970,4 +972,26 @@ class vmmManager(gobject.GObject):
|
||||||
logging.debug("Deactivating connection %s" % conn.get_uri())
|
logging.debug("Deactivating connection %s" % conn.get_uri())
|
||||||
conn.pause()
|
conn.pause()
|
||||||
|
|
||||||
|
def _connect_error(self, conn, details):
|
||||||
|
if conn.get_driver() == "xen" and not conn.is_remote():
|
||||||
|
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
|
||||||
|
gtk.BUTTONS_CLOSE,
|
||||||
|
_("Unable to open a connection to the Xen hypervisor/daemon.\n\n" +
|
||||||
|
"Verify that:\n" +
|
||||||
|
" - A Xen host kernel was booted\n" +
|
||||||
|
" - The Xen service has been started\n"),
|
||||||
|
details)
|
||||||
|
else:
|
||||||
|
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
|
||||||
|
gtk.BUTTONS_CLOSE,
|
||||||
|
_("Unable to open a connection to the libvirt management daemon.\n\n" +
|
||||||
|
"Verify that:\n" +
|
||||||
|
" - The 'libvirtd' daemon has been started\n"),
|
||||||
|
details)
|
||||||
|
dg.set_title(_("Virtual Machine Manager Connection Failure"))
|
||||||
|
dg.run()
|
||||||
|
dg.hide()
|
||||||
|
dg.destroy()
|
||||||
|
|
||||||
|
|
||||||
gobject.type_register(vmmManager)
|
gobject.type_register(vmmManager)
|
||||||
|
|
Loading…
Reference in New Issue