[virt-tools-list] [RFC Patch v3] Support job cancellation for migration, save functions
Wen Congyang
wency at cn.fujitsu.com
Wed Dec 8 03:41:50 UTC 2010
# HG changeset patch
# User Wen Congyang <wency at cn.fujitsu.com>
# Date 1291777487 -28800
# Node ID 91a8075863a66d09eb183c98aa3d57a750ffcee0
# Parent eafa58f4f95042a6ddf8ca96bc2aefb9bebe88ec
Support job cancellation for migration, save functions
diff -r eafa58f4f950 -r 91a8075863a6 src/virtManager/asyncjob.py
--- a/src/virtManager/asyncjob.py Mon Dec 06 21:38:05 2010 -0500
+++ b/src/virtManager/asyncjob.py Wed Dec 08 11:04:47 2010 +0800
@@ -24,6 +24,7 @@
import gobject
from virtManager import util
+from virtManager.error import vmmErrorDialog
# This thin wrapper only exists so we can put debugging
# code in the run() method every now & then
@@ -40,7 +41,7 @@
def __init__(self, config, callback, args=None,
text=_("Please wait a few moments..."),
title=_("Operation in progress"),
- run_main=True):
+ run_main=True, cancel_back=None, cancel_args=[]):
gobject.GObject.__init__(self)
self.config = config
self.run_main = bool(run_main)
@@ -48,6 +49,20 @@
self.window = gtk.glade.XML(config.get_glade_dir() + \
"/vmm-progress.glade",
"vmm-progress", domain="virt-manager")
+ self.topwin = self.window.get_widget("vmm-progress")
+ self.err = vmmErrorDialog(self.topwin)
+ self.window.signal_autoconnect({
+ "on_async_job_delete_event" : self.delete,
+ "on_async_job_cancel_clicked" : self.cancel,
+ })
+ self.cancel_job = cancel_back
+ self.cancel_args = cancel_args
+ self.cancel_args.append(self)
+ if self.cancel_job:
+ self.window.get_widget("cancel-async-job").show()
+ else:
+ self.window.get_widget("cancel-async-job").hide()
+ self.job_canceled = False
self.window.get_widget("pbar-text").set_text(text)
self.topwin = self.window.get_widget("vmm-progress")
@@ -89,6 +104,26 @@
self.topwin.destroy()
+ def delete(self, ignore1=None, ignore2=None):
+ thread_active = (self.bg_thread.isAlive() or not self.run_main)
+ if self.cancel_job and thread_active:
+ res = self.err.warn_chkbox(
+ text1=_("Cancel the job before closing window?"),
+ buttons=gtk.BUTTONS_YES_NO)
+ if res:
+ # The job may end after we click 'Yes', so check whether the
+ # thread is active again
+ thread_active = (self.bg_thread.isAlive() or not self.run_main)
+ if thread_active:
+ self.cancel()
+
+ def show_warning(self, summary):
+ self.err.ok(summary)
+
+ def cancel(self, ignore1=None, ignore2=None):
+ if self.cancel_job:
+ self.cancel_job(*self.cancel_args)
+
def pulse_pbar(self, progress="", stage=None):
gtk.gdk.threads_enter()
try:
diff -r eafa58f4f950 -r 91a8075863a6 src/virtManager/domain.py
--- a/src/virtManager/domain.py Mon Dec 06 21:38:05 2010 -0500
+++ b/src/virtManager/domain.py Wed Dec 08 11:04:47 2010 +0800
@@ -828,6 +828,8 @@
self.getvcpus_supported = support.check_domain_support(self._backend,
support.SUPPORT_DOMAIN_GETVCPUS)
self.managedsave_supported = self.connection.get_dom_managedsave_supported(self._backend)
+ self.getjobinfo_supported = support.check_domain_support(self._backend,
+ support.SUPPORT_DOMAIN_JOB_INFO)
self.toggle_sample_network_traffic()
self.toggle_sample_disk_io()
@@ -1001,6 +1003,9 @@
if self.get_autostart() != val:
self._backend.setAutostart(val)
+ def abort_job(self):
+ self._backend.abortJob()
+
def migrate_set_max_downtime(self, max_downtime, flag=0):
self._backend.migrateSetMaxDowntime(max_downtime, flag)
diff -r eafa58f4f950 -r 91a8075863a6 src/virtManager/engine.py
--- a/src/virtManager/engine.py Mon Dec 06 21:38:05 2010 -0500
+++ b/src/virtManager/engine.py Wed Dec 08 11:04:47 2010 +0800
@@ -825,15 +825,37 @@
if not path:
return
+ if vm.getjobinfo_supported:
+ _cancel_back=self._save_cancel
+ _cancel_args=[vm]
+ else:
+ _cancel_back=None
+ _cancel_args=[None]
+
progWin = vmmAsyncJob(self.config, self._save_callback,
[vm, path],
- _("Saving Virtual Machine"))
+ _("Saving Virtual Machine"),
+ cancel_back=_cancel_back,
+ cancel_args=_cancel_args)
progWin.run()
error, details = progWin.get_error()
if error is not None:
src.err.show_err(_("Error saving domain: %s") % error, details)
+ def _save_cancel(self, vm, asyncjob):
+ if not vm:
+ return
+
+ try:
+ vm.abort_job()
+ except Exception, e:
+ asyncjob.show_warning(str(e))
+ return
+
+ asyncjob.job_canceled = True
+ return
+
def _save_callback(self, vm, file_to_save, asyncjob):
try:
conn = util.dup_conn(self.config, vm.connection,
@@ -842,7 +864,11 @@
newvm.save(file_to_save)
except Exception, e:
- asyncjob.set_error(str(e), "".join(traceback.format_exc()))
+ if not (isinstance(e, libvirt.libvirtError) and
+ asyncjob.job_canceled):
+ # If job is cancelled, we should not report the error
+ # to user.
+ asyncjob.set_error(str(e), "".join(traceback.format_exc()))
def _do_restore_domain(self, src, uri):
conn = self._lookup_connection(uri)
diff -r eafa58f4f950 -r 91a8075863a6 src/virtManager/migrate.py
--- a/src/virtManager/migrate.py Mon Dec 06 21:38:05 2010 -0500
+++ b/src/virtManager/migrate.py Wed Dec 08 11:04:47 2010 +0800
@@ -445,13 +445,22 @@
self.topwin.set_sensitive(False)
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+ if self.vm.getjobinfo_supported:
+ _cancel_back=self.cancel_migration
+ _cancel_args=[self.vm]
+ else:
+ _cancel_back=None
+ _cancel_args=[None]
+
progWin = vmmAsyncJob(self.config, self._async_migrate,
[self.vm, destconn, uri, rate, live, secure,
max_downtime],
title=_("Migrating VM '%s'" % self.vm.get_name()),
text=(_("Migrating VM '%s' from %s to %s. "
"This may take awhile.") %
- (self.vm.get_name(), srchost, dsthost)))
+ (self.vm.get_name(), srchost, dsthost)),
+ cancel_back=_cancel_back,
+ cancel_args=_cancel_args)
progWin.run()
error, details = progWin.get_error()
@@ -481,6 +490,19 @@
logging.warning("Error setting migrate downtime: %s" % e)
return False
+ def cancel_migration(self, vm, asyncjob):
+ if not vm:
+ return
+
+ try:
+ vm.abort_job()
+ except Exception, e:
+ asyncjob.show_warning(str(e))
+ return
+
+ asyncjob.job_canceled = True
+ return
+
def _async_migrate(self, origvm, origdconn, migrate_uri, rate, live,
secure, max_downtime, asyncjob):
errinfo = None
@@ -511,8 +533,12 @@
if timer:
gobject.source_remove(timer)
except Exception, e:
- errinfo = (str(e), ("Unable to migrate guest:\n %s" %
- "".join(traceback.format_exc())))
+ if not (isinstance(e, libvirt.libvirtError) and
+ asyncjob.job_canceled):
+ # If job is cancelled, we should not report the error
+ # to user.
+ errinfo = (str(e), ("Unable to migrate guest:\n %s" %
+ "".join(traceback.format_exc())))
finally:
if errinfo:
asyncjob.set_error(errinfo[0], errinfo[1])
diff -r eafa58f4f950 -r 91a8075863a6 src/vmm-progress.glade
--- a/src/vmm-progress.glade Mon Dec 06 21:38:05 2010 -0500
+++ b/src/vmm-progress.glade Wed Dec 08 11:04:47 2010 +0800
@@ -12,6 +12,7 @@
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="urgency_hint">True</property>
+ <signal name="delete_event" handler="on_async_job_delete_event"/>
<child>
<widget class="GtkAlignment" id="alignment134">
<property name="visible">True</property>
@@ -82,6 +83,40 @@
<property name="position">2</property>
</packing>
</child>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="cancel-async-job">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="on_async_job_cancel_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
</widget>
</child>
</widget>
More information about the virt-tools-list
mailing list