[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