[virt-tools-list] [RFC Patch v2] Support job cancellation for migration, save functions
Wen Congyang
wency at cn.fujitsu.com
Wed Dec 1 03:35:15 UTC 2010
# HG changeset patch
# User Wen Congyang <wency at cn.fujitsu.com>
# Date 1291173826 -28800
# Node ID da5771e13f5a395c3fff8bcbdf2769d308034744
# Parent dedbf8d0d5a34399a2baa8422b0f154a1c243bb0
Support job cancellation for migration, save functions
I do not use the API libvirt.jobinfo() to check whether the job is cancelled,
because the jobinfo is cleared when job ends...
diff -r dedbf8d0d5a3 -r da5771e13f5a src/virtManager/asyncjob.py
--- a/src/virtManager/asyncjob.py Tue Nov 30 10:52:11 2010 -0500
+++ b/src/virtManager/asyncjob.py Wed Dec 01 11:23:46 2010 +0800
@@ -40,6 +40,7 @@
class vmmAsyncJob(gobject.GObject):
def __init__(self, config, callback, args=None,
+ cancel_back=None, cancel_args=None,
text=_("Please wait a few moments..."),
title=_("Operation in progress"),
run_main=True):
@@ -50,6 +51,16 @@
self.window = gtk.glade.XML(config.get_glade_dir() + \
"/vmm-progress.glade",
"vmm-progress", domain="virt-manager")
+ self.window.signal_autoconnect({
+ "on_async_job_delete_event" : self.cancel,
+ "on_async_job_cancel_clicked" : self.cancel,
+ })
+ self.cancel_job = cancel_back
+ self.cancel_args = cancel_args
+ if self.cancel_job:
+ self.window.get_widget("cancel-async-job").set_sensitive(True)
+ else:
+ self.window.get_widget("cancel-async-job").set_sensitive(False)
self.window.get_widget("pbar-text").set_text(text)
self.topwin = self.window.get_widget("vmm-progress")
@@ -91,6 +102,10 @@
self.topwin.destroy()
+ 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 dedbf8d0d5a3 -r da5771e13f5a src/virtManager/domain.py
--- a/src/virtManager/domain.py Tue Nov 30 10:52:11 2010 -0500
+++ b/src/virtManager/domain.py Wed Dec 01 11:23:46 2010 +0800
@@ -1001,6 +1001,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 dedbf8d0d5a3 -r da5771e13f5a src/virtManager/engine.py
--- a/src/virtManager/engine.py Tue Nov 30 10:52:11 2010 -0500
+++ b/src/virtManager/engine.py Wed Dec 01 11:23:46 2010 +0800
@@ -828,8 +828,10 @@
if not path:
return
+ job_info = {"is_cancelled" : False}
progWin = vmmAsyncJob(self.config, self._save_callback,
- [vm, path],
+ [vm, path, job_info],
+ self._save_cancel, [vm, job_info],
_("Saving Virtual Machine"))
progWin.run()
error, details = progWin.get_error()
@@ -837,7 +839,12 @@
if error is not None:
src.err.show_err(_("Error saving domain: %s") % error, details)
- def _save_callback(self, vm, file_to_save, asyncjob):
+ def _save_cancel(self, vm, job_info):
+ vm.abort_job()
+ job_info["is_cancelled"] = True
+ return
+
+ def _save_callback(self, vm, file_to_save, job_info, asyncjob):
try:
conn = util.dup_conn(self.config, vm.connection,
return_conn_class=True)
@@ -845,7 +852,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
+ job_info["is_cancelled"]):
+ # 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 dedbf8d0d5a3 -r da5771e13f5a src/virtManager/migrate.py
--- a/src/virtManager/migrate.py Tue Nov 30 10:52:11 2010 -0500
+++ b/src/virtManager/migrate.py Wed Dec 01 11:23:46 2010 +0800
@@ -448,9 +448,11 @@
self.topwin.set_sensitive(False)
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+ job_info = {"is_cancelled" : False}
progWin = vmmAsyncJob(self.config, self._async_migrate,
[self.vm, destconn, uri, rate, live, secure,
- max_downtime],
+ max_downtime, job_info],
+ self.cancel_migration, [self.vm, job_info],
title=_("Migrating VM '%s'" % self.vm.get_name()),
text=(_("Migrating VM '%s' from %s to %s. "
"This may take awhile.") %
@@ -484,8 +486,13 @@
logging.warning("Error setting migrate downtime: %s" % e)
return False
+ def cancel_migration(self, vm, job_info):
+ vm.abort_job()
+ job_info["is_cancelled"] = True
+ return
+
def _async_migrate(self, origvm, origdconn, migrate_uri, rate, live,
- secure, max_downtime, asyncjob):
+ secure, max_downtime, job_info, asyncjob):
errinfo = None
try:
try:
@@ -514,8 +521,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
+ job_info["is_cancelled"]):
+ # 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 dedbf8d0d5a3 -r da5771e13f5a src/vmm-progress.glade
--- a/src/vmm-progress.glade Tue Nov 30 10:52:11 2010 -0500
+++ b/src/vmm-progress.glade Wed Dec 01 11:23:46 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