mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-01-08 21:18:04 +03:00
asyncjob: Fix issues with multiple dialogs (bz 1003101)
Basically, drop usage of nested main loops. As has been documented in other commit messages, we use nested main loops in ways they aren't supposed to be used. They gave us async behavior that would block callers, but had weird behavior in some edge cases. Switch to having async dialogs be 100% async, requiring the user to pass in a completion callback which is triggered after the async action is complete.
This commit is contained in:
parent
0551d8956b
commit
6869760732
@ -893,37 +893,6 @@ class vmmAddHardware(vmmGObjectUI):
|
||||
notebook.get_nth_page(page).show()
|
||||
notebook.set_current_page(page)
|
||||
|
||||
def finish(self, ignore=None):
|
||||
notebook = self.widget("create-pages")
|
||||
try:
|
||||
if self.validate(notebook.get_current_page()) is False:
|
||||
return
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Uncaught error validating hardware "
|
||||
"input: %s") % str(e))
|
||||
return
|
||||
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
try:
|
||||
failure, errinfo = self.add_device()
|
||||
error, details = errinfo or (None, None)
|
||||
except Exception, e:
|
||||
failure = True
|
||||
error = _("Unable to add device: %s") % str(e)
|
||||
details = "".join(traceback.format_exc())
|
||||
|
||||
if error is not None:
|
||||
self.err.show_err(error, details=details)
|
||||
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
self._dev = None
|
||||
if not failure:
|
||||
self.close()
|
||||
|
||||
def show_pair_combo(self, basename, show_combo):
|
||||
combo = self.widget(basename + "-combo")
|
||||
label = self.widget(basename + "-label")
|
||||
@ -1137,36 +1106,12 @@ class vmmAddHardware(vmmGObjectUI):
|
||||
# Add device methods #
|
||||
######################
|
||||
|
||||
def _storage_progress(self):
|
||||
def do_file_allocate(asyncjob, disk):
|
||||
meter = asyncjob.get_meter()
|
||||
|
||||
logging.debug("Starting background file allocate process")
|
||||
disk.setup(meter=meter)
|
||||
logging.debug("Allocation completed")
|
||||
|
||||
progWin = vmmAsyncJob(do_file_allocate,
|
||||
[self._dev],
|
||||
_("Creating Storage File"),
|
||||
_("Allocation of disk storage may take "
|
||||
"a few minutes to complete."),
|
||||
self.topwin)
|
||||
|
||||
return progWin.run()
|
||||
|
||||
def setup_device(self):
|
||||
if (self._dev.virtual_device_type == self._dev.VIRTUAL_DEV_DISK and
|
||||
self._dev.creating_storage()):
|
||||
return self._storage_progress()
|
||||
|
||||
return self._dev.setup()
|
||||
def setup_device(self, asyncjob):
|
||||
logging.debug("Running setup for device=%s", self._dev)
|
||||
self._dev.setup(meter=asyncjob.get_meter())
|
||||
logging.debug("Setup complete")
|
||||
|
||||
def add_device(self):
|
||||
ret = self.setup_device()
|
||||
if ret and ret[0]:
|
||||
# Encountered an error
|
||||
return (True, ret)
|
||||
|
||||
self._dev.get_xml_config()
|
||||
logging.debug("Adding device:\n" + self._dev.get_xml_config())
|
||||
|
||||
@ -1197,7 +1142,7 @@ class vmmAddHardware(vmmGObjectUI):
|
||||
modal=True)
|
||||
|
||||
if not res:
|
||||
return (False, None)
|
||||
return False
|
||||
|
||||
# Alter persistent config
|
||||
try:
|
||||
@ -1206,9 +1151,52 @@ class vmmAddHardware(vmmGObjectUI):
|
||||
self.vm.add_device(self._dev)
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Error adding device: %s" % str(e)))
|
||||
return (True, None)
|
||||
return True
|
||||
|
||||
return (False, None)
|
||||
return False
|
||||
|
||||
def _finish_cb(self, error, details):
|
||||
failure = True
|
||||
if not error:
|
||||
try:
|
||||
failure = self.add_device()
|
||||
except Exception, e:
|
||||
failure = True
|
||||
error = _("Unable to add device: %s") % str(e)
|
||||
details = "".join(traceback.format_exc())
|
||||
|
||||
if error is not None:
|
||||
self.err.show_err(error, details=details)
|
||||
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
self._dev = None
|
||||
if not failure:
|
||||
self.close()
|
||||
|
||||
def finish(self, ignore=None):
|
||||
notebook = self.widget("create-pages")
|
||||
try:
|
||||
if self.validate(notebook.get_current_page()) is False:
|
||||
return
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Uncaught error validating hardware "
|
||||
"input: %s") % str(e))
|
||||
return
|
||||
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
progWin = vmmAsyncJob(self.setup_device, [],
|
||||
self._finish_cb, [],
|
||||
_("Creating device"),
|
||||
_("Depending on the device, this may take "
|
||||
"a few minutes to complete."),
|
||||
self.topwin)
|
||||
progWin.run()
|
||||
|
||||
|
||||
###########################
|
||||
|
@ -86,15 +86,6 @@ class vmmMeter(urlgrabber.progress.BaseMeter):
|
||||
self.started = False
|
||||
|
||||
|
||||
# This thin wrapper only exists so we can put debugging
|
||||
# code in the run() method every now & then
|
||||
class asyncJobWorker(threading.Thread):
|
||||
def __init__(self, callback, args):
|
||||
args = [callback] + args
|
||||
threading.Thread.__init__(self, target=cb_wrapper, args=args)
|
||||
self.daemon = True
|
||||
|
||||
|
||||
def cb_wrapper(callback, asyncjob, *args, **kwargs):
|
||||
try:
|
||||
callback(asyncjob, *args, **kwargs)
|
||||
@ -108,8 +99,22 @@ def cb_wrapper(callback, asyncjob, *args, **kwargs):
|
||||
asyncjob.set_error(str(e), "".join(traceback.format_exc()))
|
||||
|
||||
|
||||
def _simple_async_done_cb(error, details, errorintro,
|
||||
errorcb, parent, finish_cb):
|
||||
if error:
|
||||
if errorcb:
|
||||
errorcb(error, details)
|
||||
else:
|
||||
error = errorintro + ": " + error
|
||||
parent.err.show_err(error,
|
||||
details=details)
|
||||
|
||||
if finish_cb:
|
||||
finish_cb()
|
||||
|
||||
|
||||
def _simple_async(callback, args, title, text, parent, errorintro,
|
||||
show_progress, simplecb, errorcb):
|
||||
show_progress, simplecb, errorcb, finish_cb):
|
||||
"""
|
||||
@show_progress: Whether to actually show a progress dialog
|
||||
@simplecb: If true, build a callback wrapper that ignores the asyncjob
|
||||
@ -122,18 +127,12 @@ def _simple_async(callback, args, title, text, parent, errorintro,
|
||||
callback(*args, **kwargs)
|
||||
docb = tmpcb
|
||||
|
||||
asyncjob = vmmAsyncJob(docb, args, title, text, parent.topwin,
|
||||
asyncjob = vmmAsyncJob(docb, args,
|
||||
_simple_async_done_cb,
|
||||
(errorintro, errorcb, parent, finish_cb),
|
||||
title, text, parent.topwin,
|
||||
show_progress=show_progress)
|
||||
error, details = asyncjob.run()
|
||||
if error is None:
|
||||
return
|
||||
|
||||
if errorcb:
|
||||
errorcb(error, details)
|
||||
else:
|
||||
error = errorintro + ": " + error
|
||||
parent.err.show_err(error,
|
||||
details=details)
|
||||
asyncjob.run()
|
||||
|
||||
|
||||
def idle_wrapper(fn):
|
||||
@ -148,18 +147,22 @@ class vmmAsyncJob(vmmGObjectUI):
|
||||
"""
|
||||
@staticmethod
|
||||
def simple_async(callback, args, title, text, parent, errorintro,
|
||||
simplecb=True, errorcb=None):
|
||||
_simple_async(callback, args, title, text, parent, errorintro, True,
|
||||
simplecb, errorcb)
|
||||
simplecb=True, errorcb=None, finish_cb=None):
|
||||
_simple_async(callback, args,
|
||||
title, text, parent, errorintro, True,
|
||||
simplecb, errorcb, finish_cb)
|
||||
|
||||
@staticmethod
|
||||
def simple_async_noshow(callback, args, parent, errorintro,
|
||||
simplecb=True, errorcb=None):
|
||||
_simple_async(callback, args, "", "", parent, errorintro, False,
|
||||
simplecb, errorcb)
|
||||
simplecb=True, errorcb=None, finish_cb=None):
|
||||
_simple_async(callback, args,
|
||||
"", "", parent, errorintro, False,
|
||||
simplecb, errorcb, finish_cb)
|
||||
|
||||
|
||||
def __init__(self, callback, args, title, text, parent,
|
||||
def __init__(self,
|
||||
callback, args, finish_cb, finish_args,
|
||||
title, text, parent,
|
||||
show_progress=True, cancel_cb=None):
|
||||
"""
|
||||
@show_progress: If False, don't actually show a progress dialog
|
||||
@ -175,15 +178,19 @@ class vmmAsyncJob(vmmGObjectUI):
|
||||
self.cancel_cb = cancel_cb[0]
|
||||
self.cancel_args = [self] + list(cancel_cb[1:])
|
||||
self.job_canceled = False
|
||||
self._finish_cb = finish_cb
|
||||
self._finish_args = finish_args or ()
|
||||
|
||||
self._timer = None
|
||||
self._error_info = None
|
||||
self._data = None
|
||||
|
||||
self._is_pulsing = True
|
||||
self._meter = None
|
||||
|
||||
args = [self] + args
|
||||
self._bg_thread = asyncJobWorker(callback, args)
|
||||
self._bg_thread = threading.Thread(target=cb_wrapper,
|
||||
args=[callback, self] + args)
|
||||
self._bg_thread.daemon = True
|
||||
logging.debug("Creating async job for function cb=%s", callback)
|
||||
|
||||
self.builder.connect_signals({
|
||||
@ -278,8 +285,19 @@ class vmmAsyncJob(vmmGObjectUI):
|
||||
self.widget("warning-box").show()
|
||||
self.widget("warning-text").set_markup(markup)
|
||||
|
||||
def _thread_finished(self):
|
||||
GLib.source_remove(self._timer)
|
||||
self.topwin.destroy()
|
||||
self.cleanup()
|
||||
|
||||
error = None
|
||||
details = None
|
||||
if self._error_info:
|
||||
error, details = self._error_info
|
||||
self._finish_cb(error, details, *self._finish_args)
|
||||
|
||||
def run(self):
|
||||
timer = GLib.timeout_add(100, self._exit_if_necessary)
|
||||
self._timer = GLib.timeout_add(100, self._exit_if_necessary)
|
||||
|
||||
if self.show_progress:
|
||||
self.topwin.present()
|
||||
@ -287,15 +305,7 @@ class vmmAsyncJob(vmmGObjectUI):
|
||||
if not self.cancel_cb and self.show_progress:
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
self._bg_thread.start()
|
||||
Gtk.main()
|
||||
|
||||
GLib.source_remove(timer)
|
||||
|
||||
self.topwin.destroy()
|
||||
self.cleanup()
|
||||
return self._error_info or (None, None)
|
||||
|
||||
|
||||
####################################################################
|
||||
@ -306,7 +316,7 @@ class vmmAsyncJob(vmmGObjectUI):
|
||||
|
||||
def _exit_if_necessary(self):
|
||||
if not self._bg_thread.is_alive():
|
||||
Gtk.main_quit()
|
||||
self._thread_finished()
|
||||
return False
|
||||
|
||||
if not self._is_pulsing or not self.show_progress:
|
||||
|
@ -783,6 +783,19 @@ class vmmCloneVM(vmmGObjectUI):
|
||||
self.clone_design = cd
|
||||
return True
|
||||
|
||||
def _finish_cb(self, error, details):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error is not None:
|
||||
error = (_("Error creating virtual machine clone '%s': %s") %
|
||||
(self.clone_design.clone_name, error))
|
||||
self.err.show_err(error, details=details)
|
||||
else:
|
||||
self.close()
|
||||
self.conn.schedule_priority_tick(pollvm=True)
|
||||
|
||||
def finish(self, src_ignore):
|
||||
try:
|
||||
if not self.validate():
|
||||
@ -792,7 +805,8 @@ class vmmCloneVM(vmmGObjectUI):
|
||||
return
|
||||
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
title = (_("Creating virtual machine clone '%s'") %
|
||||
self.clone_design.clone_name)
|
||||
@ -800,19 +814,9 @@ class vmmCloneVM(vmmGObjectUI):
|
||||
if self.clone_design.clone_disks:
|
||||
text = title + _(" and selected storage (this may take a while)")
|
||||
|
||||
progWin = vmmAsyncJob(self._async_clone, [], title, text, self.topwin)
|
||||
error, details = progWin.run()
|
||||
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error is not None:
|
||||
error = (_("Error creating virtual machine clone '%s': %s") %
|
||||
(self.clone_design.clone_name, error))
|
||||
self.err.show_err(error, details=details)
|
||||
else:
|
||||
self.close()
|
||||
self.conn.schedule_priority_tick(pollvm=True)
|
||||
progWin = vmmAsyncJob(self._async_clone, [], self._finish_cb, [],
|
||||
title, text, self.topwin)
|
||||
progWin.run()
|
||||
|
||||
def _async_clone(self, asyncjob):
|
||||
try:
|
||||
|
@ -1778,6 +1778,12 @@ class vmmCreate(vmmGObjectUI):
|
||||
break
|
||||
pagenum = self._get_next_pagenum(pagenum)
|
||||
|
||||
def _undo_finish_cursor(self):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
|
||||
def finish(self, src_ignore):
|
||||
# Validate the final page
|
||||
page = self.widget("create-pages").get_current_page()
|
||||
@ -1792,25 +1798,15 @@ class vmmCreate(vmmGObjectUI):
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
def start_install():
|
||||
if not self.get_config_customize():
|
||||
self.start_install(guest)
|
||||
if self.get_config_customize():
|
||||
try:
|
||||
self.customize(guest)
|
||||
except Exception, e:
|
||||
self._undo_finish_cursor()
|
||||
self.err.show_err(_("Error starting installation: ") + str(e))
|
||||
return
|
||||
|
||||
self.customize(guest)
|
||||
|
||||
self._check_start_error(start_install)
|
||||
|
||||
def _undo_finish(self, ignore=None):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
def _check_start_error(self, cb, *args, **kwargs):
|
||||
try:
|
||||
cb(*args, **kwargs)
|
||||
except Exception, e:
|
||||
self._undo_finish()
|
||||
self.err.show_err(_("Error starting installation: ") + str(e))
|
||||
else:
|
||||
self.start_install(guest)
|
||||
|
||||
def customize(self, guest):
|
||||
virtinst_guest = vmmDomainVirtinst(self.conn, guest, self.guest.uuid)
|
||||
@ -1826,11 +1822,11 @@ class vmmCreate(vmmGObjectUI):
|
||||
cleanup_config_window()
|
||||
if not self.is_visible():
|
||||
return
|
||||
self._check_start_error(self.start_install, guest)
|
||||
self.start_install(guest)
|
||||
|
||||
def details_closed(ignore):
|
||||
cleanup_config_window()
|
||||
self._undo_finish()
|
||||
self._undo_finish_cursor()
|
||||
self.widget("summary-customize").set_active(False)
|
||||
|
||||
cleanup_config_window()
|
||||
@ -1845,19 +1841,8 @@ class vmmCreate(vmmGObjectUI):
|
||||
details_closed))
|
||||
self.config_window.show()
|
||||
|
||||
def start_install(self, guest):
|
||||
progWin = vmmAsyncJob(self.do_install, [guest],
|
||||
_("Creating Virtual Machine"),
|
||||
_("The virtual machine is now being "
|
||||
"created. Allocation of disk storage "
|
||||
"and retrieval of the installation "
|
||||
"images may take a few minutes to "
|
||||
"complete."),
|
||||
self.topwin)
|
||||
error, details = progWin.run()
|
||||
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
def _install_finished_cb(self, error, details):
|
||||
self._undo_finish_cursor()
|
||||
|
||||
if error:
|
||||
error = (_("Unable to complete install: '%s'") % error)
|
||||
@ -1869,7 +1854,20 @@ class vmmCreate(vmmGObjectUI):
|
||||
self.close()
|
||||
|
||||
# Launch details dialog for new VM
|
||||
self.emit("action-show-vm", self.conn.get_uri(), guest.uuid)
|
||||
self.emit("action-show-vm", self.conn.get_uri(), self.guest.uuid)
|
||||
|
||||
|
||||
def start_install(self, guest):
|
||||
progWin = vmmAsyncJob(self.do_install, [guest],
|
||||
self._install_finished_cb, [],
|
||||
_("Creating Virtual Machine"),
|
||||
_("The virtual machine is now being "
|
||||
"created. Allocation of disk storage "
|
||||
"and retrieval of the installation "
|
||||
"images may take a few minutes to "
|
||||
"complete."),
|
||||
self.topwin)
|
||||
progWin.run()
|
||||
|
||||
def do_install(self, asyncjob, guest):
|
||||
meter = asyncjob.get_meter()
|
||||
|
@ -1096,27 +1096,10 @@ class vmmCreateInterface(vmmGObjectUI):
|
||||
# Creation routines #
|
||||
#####################
|
||||
|
||||
def finish(self, src):
|
||||
|
||||
# Validate the final page
|
||||
page = self.widget("pages").get_current_page()
|
||||
if self.validate(page) is not True:
|
||||
return False
|
||||
|
||||
activate = self.widget("interface-activate").get_active()
|
||||
|
||||
# Start the install
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
progWin = vmmAsyncJob(self.do_install, [activate],
|
||||
_("Creating virtual interface"),
|
||||
_("The virtual interface is now being created."),
|
||||
self.topwin)
|
||||
error, details = progWin.run()
|
||||
|
||||
def _finish_cb(self, error, details):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error:
|
||||
error = _("Error creating interface: '%s'") % error
|
||||
@ -1126,6 +1109,26 @@ class vmmCreateInterface(vmmGObjectUI):
|
||||
self.conn.schedule_priority_tick(polliface=True)
|
||||
self.close()
|
||||
|
||||
def finish(self, src):
|
||||
# Validate the final page
|
||||
page = self.widget("pages").get_current_page()
|
||||
if self.validate(page) is not True:
|
||||
return False
|
||||
|
||||
activate = self.widget("interface-activate").get_active()
|
||||
|
||||
# Start the install
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
progWin = vmmAsyncJob(self.do_install, [activate],
|
||||
self._finish_cb, [],
|
||||
_("Creating virtual interface"),
|
||||
_("The virtual interface is now being created."),
|
||||
self.topwin)
|
||||
progWin.run()
|
||||
|
||||
def do_install(self, asyncjob, activate):
|
||||
meter = asyncjob.get_meter()
|
||||
self.interface.install(meter, create=activate)
|
||||
|
@ -432,20 +432,10 @@ class vmmCreatePool(vmmGObjectUI):
|
||||
self.widget("pool-forward").show()
|
||||
self.widget("pool-pages").prev_page()
|
||||
|
||||
def finish(self):
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
build = self.widget("pool-build").get_active()
|
||||
|
||||
progWin = vmmAsyncJob(self._async_pool_create, [build],
|
||||
_("Creating storage pool..."),
|
||||
_("Creating the storage pool may take a "
|
||||
"while..."),
|
||||
self.topwin)
|
||||
error, details = progWin.run()
|
||||
|
||||
def _finish_cb(self, error, details):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error:
|
||||
error = _("Error creating pool: %s") % error
|
||||
@ -455,6 +445,20 @@ class vmmCreatePool(vmmGObjectUI):
|
||||
self.conn.schedule_priority_tick(pollpool=True)
|
||||
self.close()
|
||||
|
||||
def finish(self):
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
build = self.widget("pool-build").get_active()
|
||||
|
||||
progWin = vmmAsyncJob(self._async_pool_create, [build],
|
||||
self._finish_cb, [],
|
||||
_("Creating storage pool..."),
|
||||
_("Creating the storage pool may take a "
|
||||
"while..."),
|
||||
self.topwin)
|
||||
progWin.run()
|
||||
|
||||
def _async_pool_create(self, asyncjob, build):
|
||||
meter = asyncjob.get_meter()
|
||||
|
||||
|
@ -217,6 +217,20 @@ class vmmCreateVolume(vmmGObjectUI):
|
||||
if cap < alloc:
|
||||
alloc_widget.set_value(cap)
|
||||
|
||||
def _finish_cb(self, error, details):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error:
|
||||
error = _("Error creating vol: %s") % error
|
||||
self.show_err(error,
|
||||
details=details)
|
||||
else:
|
||||
# vol-created will refresh the parent pool
|
||||
self.emit("vol-created")
|
||||
self.close()
|
||||
|
||||
def finish(self, src_ignore):
|
||||
try:
|
||||
if not self.validate():
|
||||
@ -229,26 +243,16 @@ class vmmCreateVolume(vmmGObjectUI):
|
||||
self.vol.get_xml_config())
|
||||
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
progWin = vmmAsyncJob(self._async_vol_create, [],
|
||||
self._finish_cb, [],
|
||||
_("Creating storage volume..."),
|
||||
_("Creating the storage volume may take a "
|
||||
"while..."),
|
||||
self.topwin)
|
||||
error, details = progWin.run()
|
||||
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error:
|
||||
error = _("Error creating vol: %s") % error
|
||||
self.show_err(error,
|
||||
details=details)
|
||||
else:
|
||||
# vol-created will refresh the parent pool
|
||||
self.emit("vol-created")
|
||||
self.close()
|
||||
progWin.run()
|
||||
|
||||
def _async_vol_create(self, asyncjob):
|
||||
conn = self.conn.get_backend()
|
||||
|
@ -131,6 +131,17 @@ class vmmDeleteDialog(vmmGObjectUI):
|
||||
paths.append(row[STORAGE_ROW_PATH])
|
||||
return paths
|
||||
|
||||
def _finish_cb(self, error, details):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error is not None:
|
||||
self.err.show_err(error, details=details)
|
||||
|
||||
self.conn.schedule_priority_tick(pollvm=True)
|
||||
self.close()
|
||||
|
||||
def finish(self, src_ignore):
|
||||
devs = self.get_paths_to_delete()
|
||||
|
||||
@ -146,7 +157,8 @@ class vmmDeleteDialog(vmmGObjectUI):
|
||||
return
|
||||
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
title = _("Deleting virtual machine '%s'") % self.vm.get_name()
|
||||
text = title
|
||||
@ -154,17 +166,9 @@ class vmmDeleteDialog(vmmGObjectUI):
|
||||
text = title + _(" and selected storage (this may take a while)")
|
||||
|
||||
progWin = vmmAsyncJob(self._async_delete, [devs],
|
||||
self._finish_cb, [],
|
||||
title, text, self.topwin)
|
||||
error, details = progWin.run()
|
||||
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error is not None:
|
||||
self.err.show_err(error, details=details)
|
||||
|
||||
self.conn.schedule_priority_tick(pollvm=True)
|
||||
self.close()
|
||||
progWin.run()
|
||||
|
||||
def _async_delete(self, asyncjob, paths):
|
||||
storage_errors = []
|
||||
|
@ -912,16 +912,17 @@ class vmmEngine(vmmGObject):
|
||||
|
||||
def cb(asyncjob):
|
||||
vm.save(path, meter=asyncjob.get_meter())
|
||||
def finish_cb(error, details):
|
||||
if error is not None:
|
||||
error = _("Error saving domain: %s") % error
|
||||
src.err.show_err(error, details=details)
|
||||
|
||||
progWin = vmmAsyncJob(cb, [],
|
||||
finish_cb, [],
|
||||
_("Saving Virtual Machine"),
|
||||
_("Saving virtual machine memory to disk "),
|
||||
src.topwin, cancel_cb=_cancel_cb)
|
||||
error, details = progWin.run()
|
||||
|
||||
if error is not None:
|
||||
error = _("Error saving domain: %s") % error
|
||||
src.err.show_err(error, details=details)
|
||||
progWin.run()
|
||||
|
||||
def _save_cancel(self, asyncjob, vm):
|
||||
logging.debug("Cancelling save job")
|
||||
|
@ -443,6 +443,20 @@ class vmmMigrateDialog(vmmGObjectUI):
|
||||
|
||||
return True
|
||||
|
||||
def _finish_cb(self, error, details, destconn):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error:
|
||||
error = _("Unable to migrate guest: %s") % error
|
||||
self.err.show_err(error,
|
||||
details=details)
|
||||
else:
|
||||
self.conn.schedule_priority_tick(pollvm=True)
|
||||
destconn.schedule_priority_tick(pollvm=True)
|
||||
self.close()
|
||||
|
||||
def finish(self, src_ignore):
|
||||
try:
|
||||
if not self.validate():
|
||||
@ -467,33 +481,22 @@ class vmmMigrateDialog(vmmGObjectUI):
|
||||
return
|
||||
|
||||
self.topwin.set_sensitive(False)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.WATCH))
|
||||
|
||||
cancel_cb = None
|
||||
if self.vm.getjobinfo_supported:
|
||||
cancel_cb = (self.cancel_migration, self.vm)
|
||||
|
||||
progWin = vmmAsyncJob(self._async_migrate,
|
||||
[self.vm, destconn, uri, rate, live, secure,
|
||||
max_downtime],
|
||||
_("Migrating VM '%s'" % self.vm.get_name()),
|
||||
(_("Migrating VM '%s' from %s to %s. "
|
||||
"This may take a while.") %
|
||||
(self.vm.get_name(), srchost, dsthost)),
|
||||
self.topwin, cancel_cb=cancel_cb)
|
||||
error, details = progWin.run()
|
||||
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error:
|
||||
error = _("Unable to migrate guest: %s") % error
|
||||
self.err.show_err(error,
|
||||
details=details)
|
||||
else:
|
||||
self.conn.schedule_priority_tick(pollvm=True)
|
||||
destconn.schedule_priority_tick(pollvm=True)
|
||||
self.close()
|
||||
progWin = vmmAsyncJob(
|
||||
self._async_migrate,
|
||||
[self.vm, destconn, uri, rate, live, secure, max_downtime],
|
||||
self._finish_cb, [destconn],
|
||||
_("Migrating VM '%s'" % self.vm.get_name()),
|
||||
(_("Migrating VM '%s' from %s to %s. This may take a while.") %
|
||||
(self.vm.get_name(), srchost, dsthost)),
|
||||
self.topwin, cancel_cb=cancel_cb)
|
||||
progWin.run()
|
||||
|
||||
def _async_set_max_downtime(self, vm, max_downtime, migrate_thread):
|
||||
if not migrate_thread.isAlive():
|
||||
|
@ -261,6 +261,18 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
|
||||
# XXX refresh in place
|
||||
|
||||
def _finish_cb(self, error, details):
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error is not None:
|
||||
error = _("Error creating snapshot: %s") % error
|
||||
self.err.show_err(error, details=details)
|
||||
return
|
||||
|
||||
self._refresh_snapshots()
|
||||
|
||||
def _on_new_ok_clicked(self, ignore):
|
||||
name = self.widget("snapshot-new-name").get_text()
|
||||
|
||||
@ -278,21 +290,11 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
progWin = vmmAsyncJob(
|
||||
lambda ignore, xml: self.vm.create_snapshot(xml),
|
||||
[newsnap.get_xml_config()],
|
||||
self._finish_cb, [],
|
||||
_("Creating snapshot"),
|
||||
_("Creating virtual machine snapshot"),
|
||||
self.topwin)
|
||||
|
||||
error, details = progWin.run()
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.get_window().set_cursor(
|
||||
Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW))
|
||||
|
||||
if error is not None:
|
||||
error = _("Error creating snapshot: %s") % error
|
||||
self.err.show_err(error, details=details)
|
||||
return
|
||||
|
||||
self._refresh_snapshots()
|
||||
progWin.run()
|
||||
|
||||
def _on_add_clicked(self, ignore):
|
||||
snap = self._get_current_snapshot()
|
||||
@ -327,8 +329,8 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
vmmAsyncJob.simple_async_noshow(self.vm.revert_to_snapshot,
|
||||
[snap], self,
|
||||
_("Error reverting to snapshot '%s'") %
|
||||
snap.get_name())
|
||||
self._refresh_snapshots()
|
||||
snap.get_name(),
|
||||
finish_cb=self._refresh_snapshots)
|
||||
|
||||
def _on_delete_clicked(self, ignore):
|
||||
snap = self._get_current_snapshot()
|
||||
@ -346,8 +348,8 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
|
||||
logging.debug("Deleting snapshot '%s'", snap.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(snap.delete, [], self,
|
||||
_("Error deleting snapshot '%s'") % snap.get_name())
|
||||
self._refresh_snapshots()
|
||||
_("Error deleting snapshot '%s'") % snap.get_name(),
|
||||
finish_cb=self._refresh_snapshots)
|
||||
|
||||
|
||||
def _snapshot_selected(self, selection):
|
||||
|
Loading…
Reference in New Issue
Block a user