diff --git a/tests/uitests/test_migrate.py b/tests/uitests/test_migrate.py index 842bc14f6..b6a9908cf 100644 --- a/tests/uitests/test_migrate.py +++ b/tests/uitests/test_migrate.py @@ -102,7 +102,6 @@ class VMMMigrate(uiutils.UITestCase): uiutils.check(lambda: not progwin.showing, timeout=5) uiutils.check(lambda: not mig.showing) - def testMigrateConnMismatch(self): # Add a possible target but disconnect it self.app.uri = utils.URIs.test_default @@ -120,3 +119,35 @@ class VMMMigrate(uiutils.UITestCase): mig.find("conn-combo").find("No usable", "menu item") mig.keyCombo("F4") uiutils.check(lambda: not mig.showing) + + def testMigrateXMLEditor(self): + self.app.open(xmleditor_enabled=True) + manager = self.app.topwin + + # Add an additional connection + self._add_conn("test:///default") + + # Run it and check some values + vmname = "test-many-devices" + win = self._open_migrate(vmname) + win.find("address-text").set_text("TESTSUITE-FAKE") + + # Create a new obj with XML edited name, verify it worked + newname = "aafroofroo" + win.find("XML", "page tab").click() + xmleditor = win.find("XML editor") + newtext = xmleditor.text.replace( + ">%s<" % vmname, ">%s<" % newname) + xmleditor.set_text(newtext) + win.find("Migrate", "push button").click() + uiutils.check(lambda: not win.showing, timeout=10) + + manager.find(newname, "table cell") + + # Do standard xmleditor tests + win = self._open_migrate(vmname) + win.find("address-text").set_text("TESTSUITE-FAKE") + finish = win.find("Migrate", "push button") + self._test_xmleditor_interactions(win, finish) + win.find("Cancel", "push button").click() + uiutils.check(lambda: not win.visible) diff --git a/tests/uitests/utils.py b/tests/uitests/utils.py index 171ba0ea2..32735e1e3 100644 --- a/tests/uitests/utils.py +++ b/tests/uitests/utils.py @@ -265,7 +265,9 @@ def drag(win, x, y): """ Drag a window to the x/y coordinates """ - win.click() + time.sleep(.5) + win.click_title() + time.sleep(.5) clickX, clickY = _title_coordinates(win) dogtail.rawinput.drag((clickX, clickY), (x, y)) diff --git a/ui/migrate.ui b/ui/migrate.ui index b4250a019..21d8127ff 100644 --- a/ui/migrate.ui +++ b/ui/migrate.ui @@ -84,429 +84,112 @@ vertical 18 - + True False - vertical - 12 - - True - False - 6 - 6 - - - True - False - end - Migrating VM: - True - - - - 0 - 0 - - - - - True - False - end - Original host: - True - - - - 0 - 1 - - - - - True - False - end - New _host: - True - True - migrate-dest - - - - 0 - 2 - - - - - True - False - start - label - end - - - 1 - 0 - - - - - True - False - start - label - end - - - 1 - 1 - - - - - True - False - - - - conn-combo - - - - - 1 - 2 - - - - - False - True - 0 - - - - + True False vertical - 18 + 12 - + True False - 0 - none + 6 + 6 - + True False - 22 - - - True - False - 12 - - - True - False - 6 - 6 - - - True - False - end - _Address: - True - migrate-set-address - - - 0 - 0 - - - - - True - False - start - _Port: - True - migrate-set-port - - - 0 - 1 - - - - - True - True - False - start - True - - - - address-check - - - - - 1 - 0 - - - - - True - True - False - start - True - - - - port-check - - - - - 1 - 1 - - - - - True - False - - - True - True - - 0 - adjustment1 - - - False - True - 0 - - - - - True - False - start - Let libvirt decide - - - True - True - 1 - - - - - 2 - 1 - - - - - True - False - - - True - True - - - - address-text - - - - - False - True - 0 - - - - - True - False - start - Let libvirt decide - - - False - True - 1 - - - - - 2 - 0 - - - - - 0 - 1 - - - - - True - False - 6 - - - True - False - Tunnel migration through the libvirtd connection channel, rather than having the hypervisor open a separate network connection to the destination. The source libvirt instance connects directly to the destination libvirt instance. - -This can simplify setup since no additional firewall ports need to be open, and will encrypt migration traffic if your libvirt connection is encrypted. But it can be difficult to make this work with SSH transport. - end - M_ode: - True - migrate-mode - - - False - True - 0 - - - - - True - False - start - False - - - - False - True - 1 - - - - - 0 - 0 - - - - - True - False - 6 - - - True - False - True - 6 - - - True - False - start - gtk-dialog-warning - - - False - True - 0 - - - - - True - False - start - <span size="small">foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz</span> - True - True - 0 - 40 - - - False - True - 1 - - - - - 1 - 1 - - - - - True - False - start - False - _URI: - True - migrate-tunnel-uri - - - 0 - 0 - - - - - True - True - True - - - 1 - 0 - - - - - - - - 0 - 2 - - + end + Migrating VM: + True + + + + 0 + 0 + + + + + True + False + end + Original host: + True + + + + 0 + 1 + + + + + True + False + end + New _host: + True + True + migrate-dest + + + + 0 + 2 + + + + + True + False + start + label + end + + + 1 + 0 + + + + + True + False + start + label + end + + + 1 + 1 + + + + + True + False + + + + conn-combo - - - - True - False - <b>Connectivity</b> - True - + + 1 + 2 + @@ -516,91 +199,419 @@ This can simplify setup since no additional firewall ports need to be open, and - + True - True - 6 + False + vertical + 18 - + True False - 22 + 0 + none - + True False - 6 - 6 + 22 - + True False - By default libvirt will refuse to migrate a VM for certain configurations that could lead to malfunctioning guests, like if a disk's cache mode is not 'none'. + 12 + + + True + False + 6 + 6 + + + True + False + end + _Address: + True + migrate-set-address + + + 0 + 0 + + + + + True + False + start + _Port: + True + migrate-set-port + + + 0 + 1 + + + + + True + True + False + start + True + + + + address-check + + + + + 1 + 0 + + + + + True + True + False + start + True + + + + port-check + + + + + 1 + 1 + + + + + True + False + + + True + True + + 0 + adjustment1 + + + False + True + 0 + + + + + True + False + start + Let libvirt decide + + + True + True + 1 + + + + + 2 + 1 + + + + + True + False + + + True + True + + + + address-text + + + + + False + True + 0 + + + + + True + False + start + Let libvirt decide + + + False + True + 1 + + + + + 2 + 0 + + + + + 0 + 1 + + + + + True + False + 6 + + + True + False + Tunnel migration through the libvirtd connection channel, rather than having the hypervisor open a separate network connection to the destination. The source libvirt instance connects directly to the destination libvirt instance. -Enabling this option tells libvirt to skip those checks. - start - A_llow unsafe: - True - migrate-unsafe +This can simplify setup since no additional firewall ports need to be open, and will encrypt migration traffic if your libvirt connection is encrypted. But it can be difficult to make this work with SSH transport. + end + M_ode: + True + migrate-mode + + + False + True + 0 + + + + + True + False + start + False + + + + False + True + 1 + + + + + 0 + 0 + + + + + True + False + 6 + + + True + False + True + 6 + + + True + False + start + gtk-dialog-warning + + + False + True + 0 + + + + + True + False + start + <span size="small">foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz</span> + True + True + 0 + 40 + + + False + True + 1 + + + + + 1 + 1 + + + + + True + False + start + False + _URI: + True + migrate-tunnel-uri + + + 0 + 0 + + + + + True + True + True + + + 1 + 0 + + + + + + + + 0 + 2 + + - - 0 - 0 - - - - - True - True - False - start - True - - - 1 - 0 - - - - - True - False - By default, the migrated VM config is removed from the source host, and saved persistently on the destination host. The destination host is considered the new home of the VM. - -If 'temporary' is selected, the migration is considered only a temporary move: the source host maintains a copy of the VM config, and the running copy moved to the destination is only transient, and will disappear when it is shutdown. - start - _Temporary move: - True - migrate-temporary - - - 0 - 1 - - - - - True - True - False - start - True - - - 1 - 1 - + + + True + False + <b>Connectivity</b> + True + + + + False + True + 0 + - - + + True - False - Advanced options + True + 6 + + + True + False + 22 + + + True + False + 6 + 6 + + + True + False + By default libvirt will refuse to migrate a VM for certain configurations that could lead to malfunctioning guests, like if a disk's cache mode is not 'none'. + +Enabling this option tells libvirt to skip those checks. + start + A_llow unsafe: + True + migrate-unsafe + + + 0 + 0 + + + + + True + True + False + start + True + + + 1 + 0 + + + + + True + False + By default, the migrated VM config is removed from the source host, and saved persistently on the destination host. The destination host is considered the new home of the VM. + +If 'temporary' is selected, the migration is considered only a temporary move: the source host maintains a copy of the VM config, and the running copy moved to the destination is only transient, and will disappear when it is shutdown. + start + _Temporary move: + True + migrate-temporary + + + 0 + 1 + + + + + True + True + False + start + True + + + 1 + 1 + + + + + + + + + True + False + Advanced options + + + + False + True + 1 + @@ -610,11 +621,6 @@ If 'temporary' is selected, the migration is considered only a temporary move: t - - False - True - 1 - diff --git a/virtManager/migrate.py b/virtManager/migrate.py index 277ffacaa..331f6e503 100644 --- a/virtManager/migrate.py +++ b/virtManager/migrate.py @@ -17,6 +17,7 @@ from .asyncjob import vmmAsyncJob from .baseclass import vmmGObjectUI from .connmanager import vmmConnectionManager from .object.domain import vmmDomain +from .xmleditor import vmmXMLEditor NUM_COLS = 3 @@ -40,6 +41,12 @@ class vmmMigrateDialog(vmmGObjectUI): vmmGObjectUI.__init__(self, "migrate.ui", "vmm-migrate") self.vm = None + self._xmleditor = vmmXMLEditor(self.builder, self.topwin, + self.widget("details-box-align"), + self.widget("details-box")) + self._xmleditor.connect("xml-requested", + self._xmleditor_xml_requested_cb) + self.builder.connect_signals({ "on_vmm_migrate_delete_event": self._delete_event, "on_migrate_cancel_clicked": self._cancel_clicked, @@ -58,6 +65,8 @@ class vmmMigrateDialog(vmmGObjectUI): def _cleanup(self): self.vm = None + self._xmleditor.cleanup() + self._xmleditor = None @property def _connobjs(self): @@ -147,6 +156,8 @@ class vmmMigrateDialog(vmmGObjectUI): self.widget("migrate-temporary-label").get_tooltip_text()) def _reset_state(self): + self._xmleditor.reset_state() + title_str = _("Migrate '%(vm)s'") % { "vm": xmlutil.xml_escape(self.vm.get_name()), } @@ -348,6 +359,11 @@ class vmmMigrateDialog(vmmGObjectUI): def _finish(self): try: + xml = None + if self._xmleditor.is_xml_selected(): + xml = self._xmleditor.get_xml() + log.debug("Using XML from xmleditor:\n%s", xml) + row = uiutil.get_list_selected_row(self.widget("migrate-dest")) destlabel = row[COL_LABEL] destconn = self._connobjs.get(row[COL_URI]) @@ -378,7 +394,7 @@ class vmmMigrateDialog(vmmGObjectUI): progWin = vmmAsyncJob( self._async_migrate, - [self.vm, destconn, uri, tunnel, unsafe, temporary], + [self.vm, destconn, uri, tunnel, unsafe, temporary, xml], self._finish_cb, [destconn], _("Migrating VM '%s'") % self.vm.get_name(), (_("Migrating VM '%(name)s' to %(host)s. This may take a while.") % @@ -398,7 +414,7 @@ class vmmMigrateDialog(vmmGObjectUI): asyncjob.job_canceled = True # pragma: no cover def _async_migrate(self, asyncjob, - origvm, origdconn, migrate_uri, tunnel, unsafe, temporary): + origvm, origdconn, migrate_uri, tunnel, unsafe, temporary, xml): meter = asyncjob.get_meter() srcconn = origvm.conn @@ -410,5 +426,12 @@ class vmmMigrateDialog(vmmGObjectUI): log.debug("Migrating vm=%s from %s to %s", vm.get_name(), srcconn.get_uri(), dstconn.get_uri()) - vm.migrate(dstconn, migrate_uri, tunnel, unsafe, temporary, + vm.migrate(dstconn, migrate_uri, tunnel, unsafe, temporary, xml, meter=meter) + + ################ + # UI listeners # + ################ + + def _xmleditor_xml_requested_cb(self, src): + self._xmleditor.set_xml(self.vm.xmlobj.get_xml()) diff --git a/virtManager/object/domain.py b/virtManager/object/domain.py index 31afb8564..e4103d8fb 100644 --- a/virtManager/object/domain.py +++ b/virtManager/object/domain.py @@ -1388,7 +1388,7 @@ class vmmDomain(vmmLibvirtObject): def migrate(self, destconn, dest_uri=None, - tunnel=False, unsafe=False, temporary=False, meter=None): + tunnel=False, unsafe=False, temporary=False, xml=None, meter=None): self._cancel_set_time() self._install_abort = True @@ -1417,12 +1417,15 @@ class vmmDomain(vmmLibvirtObject): params = {} if dest_uri and not tunnel: params[libvirt.VIR_MIGRATE_PARAM_URI] = dest_uri + if xml: + params[libvirt.VIR_MIGRATE_PARAM_DEST_XML] = xml if self.conn.is_test() and "TESTSUITE-FAKE" in (dest_uri or ""): # If using the test driver and a special URI, fake successful # migration so we can test more of the migration wizard time.sleep(3) - xml = self.get_xml_to_define() + if not xml: + xml = self.get_xml_to_define() destconn.define_domain(xml).create() self.delete() elif tunnel: