[virt-tools-list] [PATCH] virt-manager: Add block migration support

Eiichi Tsukata devel at etsukata.com
Sat Oct 5 14:59:36 UTC 2013


This patch adds block migration support. There are two modes: full
disk copy and incremental disk copy, which correspond to libvirt
virDomainMigrate API's flags, VIR_MIGRATE_NON_SHARED_DISK and
VIR_MIGRATE_NON_SHARED_INC. These flags are mutually exclusive,
so GUI is implemented by ComboBox.

Signed-off-by: Eiichi Tsukata <devel at etsukata.com>
---
 ui/migrate.ui            | 61 ++++++++++++++++++++++++++++++++++++++++++++++--
 virtManager/domain.py    |  7 +++++-
 virtManager/migrate.py   | 41 +++++++++++++++++++++++++++++---
 virtManager/uihelpers.py | 20 ++++++++++++++++
 4 files changed, 123 insertions(+), 6 deletions(-)

diff --git a/ui/migrate.ui b/ui/migrate.ui
index 3b81fbb..d2b5b76 100644
--- a/ui/migrate.ui
+++ b/ui/migrate.ui
@@ -296,6 +296,63 @@
                           </packing>
                         </child>
                         <child>
+                          <object class="GtkAlignment" id="alignment5">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="left_padding">6</property>
+                            <child>
+                              <object class="GtkHBox" id="migrate-block-box">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <object class="GtkLabel" id="label1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">_Block migration:</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="mnemonic_widget">migrate-set-block</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="migrate-set-block">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                    <signal name="toggled" handler="on_migrate_set_block_toggled" swapped="no"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkComboBox" id="migrate-block">
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">False</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
                           <object class="GtkHBox" id="migrate-maxdowntime-box">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
@@ -408,7 +465,7 @@
                           <packing>
                             <property name="expand">True</property>
                             <property name="fill">True</property>
-                            <property name="position">1</property>
+                            <property name="position">2</property>
                           </packing>
                         </child>
                         <child>
@@ -659,7 +716,7 @@
                           <packing>
                             <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="position">2</property>
+                            <property name="position">3</property>
                           </packing>
                         </child>
                       </object>
diff --git a/virtManager/domain.py b/virtManager/domain.py
index 4dc8a8a..6ec1beb 100644
--- a/virtManager/domain.py
+++ b/virtManager/domain.py
@@ -1322,7 +1322,7 @@ class vmmDomain(vmmLibvirtObject):
         self._backend.migrateSetMaxDowntime(max_downtime, flag)
 
     def migrate(self, destconn, interface=None, rate=0,
-                live=False, secure=False, meter=None):
+                live=False, secure=False, block=None, meter=None):
         self._install_abort = True
 
         newname = None
@@ -1335,6 +1335,11 @@ class vmmDomain(vmmLibvirtObject):
             flags |= libvirt.VIR_MIGRATE_PEER2PEER
             flags |= libvirt.VIR_MIGRATE_TUNNELLED
 
+        if block == "full":
+            flags |= libvirt.VIR_MIGRATE_NON_SHARED_DISK
+        elif block == "incremental":
+            flags |= libvirt.VIR_MIGRATE_NON_SHARED_INC
+
         destconn = destconn.get_backend().libvirtconn
         logging.debug("Migrating: conn=%s flags=%s dname=%s uri=%s rate=%s",
                       destconn, flags, newname, interface, rate)
diff --git a/virtManager/migrate.py b/virtManager/migrate.py
index 75dce35..fd39457 100644
--- a/virtManager/migrate.py
+++ b/virtManager/migrate.py
@@ -31,6 +31,7 @@ from gi.repository import Gtk
 import libvirt
 from virtinst import util
 
+from virtManager import uihelpers
 from virtManager.baseclass import vmmGObjectUI
 from virtManager.asyncjob import vmmAsyncJob
 from virtManager.domain import vmmDomain
@@ -68,6 +69,7 @@ class vmmMigrateDialog(vmmGObjectUI):
             "on_migrate_set_interface_toggled" : self.toggle_set_interface,
             "on_migrate_set_port_toggled" : self.toggle_set_port,
             "on_migrate_set_maxdowntime_toggled" : self.toggle_set_maxdowntime,
+            "on_migrate_set_block_toggled" : self.toggle_set_block,
         })
         self.bind_escape_key_close()
 
@@ -116,6 +118,9 @@ class vmmMigrateDialog(vmmGObjectUI):
         self.engine.connect("conn-removed", self.dest_remove_conn)
         self.destconn_changed(dest_combo)
 
+        block_combo = self.widget("migrate-block")
+        uihelpers.build_block_migration_combo(block_combo)
+
     def reset_state(self):
         title_str = ("<span size='large' color='white'>%s '%s'</span>" %
                      (_("Migrate"), util.xml_escape(self.vm.get_name())))
@@ -141,6 +146,7 @@ class vmmMigrateDialog(vmmGObjectUI):
 
         self.widget("migrate-rate").set_value(0)
         self.widget("migrate-secure").set_active(False)
+        self.widget("migrate-set-block").set_active(False)
 
         downtime_box = self.widget("migrate-maxdowntime-box")
         support_downtime = self.vm.support_downtime()
@@ -168,6 +174,19 @@ class vmmMigrateDialog(vmmGObjectUI):
         secure_box.set_sensitive(support_secure)
         secure_box.set_tooltip_text(secure_tooltip)
 
+        block_box = self.widget("migrate-block-box")
+        support_block = (hasattr(libvirt, "VIR_MIGRATE_NON_SHARED_DISK")
+                         and hasattr(libvirt, "VIR_MIGRATE_NON_SHARED_DISK"))
+        block_tooltip = ""
+        if not support_block:
+            secure_tooltip = _("Libvirt version does not support block "
+                               "migration.")
+
+        block_box.set_sensitive(support_block)
+        block_box.set_tooltip_text(block_tooltip)
+        block_combo = self.widget("migrate-block")
+        uihelpers.populate_block_migration_combo(block_combo)
+
         self.rebuild_dest_rows()
 
     def set_state(self, vm):
@@ -199,6 +218,10 @@ class vmmMigrateDialog(vmmGObjectUI):
         enable = src.get_active()
         self.widget("migrate-max-downtime").set_sensitive(enable)
 
+    def toggle_set_block(self, src):
+        enable = src.get_active()
+        self.widget("migrate-block").set_sensitive(enable)
+
     def toggle_set_port(self, src):
         enable = src.get_active()
         self.widget("migrate-port").set_sensitive(enable)
@@ -228,9 +251,20 @@ class vmmMigrateDialog(vmmGObjectUI):
     def get_config_secure(self):
         return self.widget("migrate-secure").get_active()
 
+    def get_config_block(self):
+        if not self.get_config_block_enabled():
+            return 0
+        combo = self.widget("migrate-block")
+        model = combo.get_model()
+        idx = combo.get_active()
+        return model[idx][0]
+
     def get_config_max_downtime_enabled(self):
         return self.widget("migrate-max-downtime").get_sensitive()
 
+    def get_config_block_enabled(self):
+        return self.widget("migrate-block").get_sensitive()
+
     def get_config_rate_enabled(self):
         return self.widget("migrate-rate").get_sensitive()
     def get_config_rate(self):
@@ -464,6 +498,7 @@ class vmmMigrateDialog(vmmGObjectUI):
             max_downtime = self.get_config_max_downtime()
             live = not self.get_config_offline()
             secure = self.get_config_secure()
+            block = self.get_config_block()
             uri = self.build_migrate_uri(destconn, srcuri)
             rate = self.get_config_rate()
             if rate:
@@ -485,7 +520,7 @@ class vmmMigrateDialog(vmmGObjectUI):
 
         progWin = vmmAsyncJob(
             self._async_migrate,
-            [self.vm, destconn, uri, rate, live, secure, max_downtime],
+            [self.vm, destconn, uri, rate, live, secure, max_downtime, block],
             self._finish_cb, [destconn],
             _("Migrating VM '%s'" % self.vm.get_name()),
             (_("Migrating VM '%s' from %s to %s. This may take a while.") %
@@ -525,7 +560,7 @@ class vmmMigrateDialog(vmmGObjectUI):
 
     def _async_migrate(self, asyncjob,
                        origvm, origdconn, migrate_uri, rate, live,
-                       secure, max_downtime):
+                       secure, max_downtime, block):
         meter = asyncjob.get_meter()
 
         srcconn = origvm.conn
@@ -545,6 +580,6 @@ class vmmMigrateDialog(vmmGObjectUI):
             timer = self.timeout_add(100, self._async_set_max_downtime,
                                      vm, max_downtime, current_thread)
 
-        vm.migrate(dstconn, migrate_uri, rate, live, secure, meter=meter)
+        vm.migrate(dstconn, migrate_uri, rate, live, secure, block, meter=meter)
         if timer:
             self.idle_add(GLib.source_remove, timer)
diff --git a/virtManager/uihelpers.py b/virtManager/uihelpers.py
index 81308a2..5d1fe78 100644
--- a/virtManager/uihelpers.py
+++ b/virtManager/uihelpers.py
@@ -1096,6 +1096,26 @@ def build_keycombo_menu(cb):
     return menu
 
 
+#########################
+# Block migration combo #
+#########################
+
+def build_block_migration_combo(combo):
+    model = Gtk.ListStore(str)
+    combo.set_model(model)
+    set_combo_text_column(combo, 0)
+
+
+def populate_block_migration_combo(combo):
+    model = combo.get_model()
+    model.clear()
+
+    model.append(["full"])
+    model.append(["incremental"])
+
+    combo.set_active(0)
+
+
 #############
 # Misc bits #
 #############
-- 
1.8.3.1




More information about the virt-tools-list mailing list