virt-manager/virt-manager-guest-add-convert_to_vnc.patch
Pavel Hrdina 1f9594fe79 virt-manager-3.2.0-4.1.el8_10
- cli: Add basic --audio type=XXX,id=Y support (RHEL-17435)
- virtinst: unify detection of duplicate console when removing device (RHEL-17435)
- virtinst: fix compare for audio devices (RHEL-17435)
- testsuite: add test-spice vm definition (RHEL-17435)
- virtinst: remove spice devices when removing last spice graphics (RHEL-17435)
- guest: add convert_to_vnc() (RHEL-17435)
- guest: remove spiceport devices when spice is removed (RHEL-17435)
- guest: convert_to_vnc: convert video device (RHEL-17435)
- virt-xml: Add `--edit --convert-to-vnc` (RHEL-17435)

Resolves: RHEL-17435
2025-01-27 12:00:57 +01:00

398 lines
13 KiB
Diff

From a6f53b7da4ac6ff0139e7a130ba875a61a877617 Mon Sep 17 00:00:00 2001
Message-ID: <a6f53b7da4ac6ff0139e7a130ba875a61a877617.1737975657.git.phrdina@redhat.com>
From: Pavel Hrdina <phrdina@redhat.com>
Date: Tue, 17 Sep 2024 10:02:59 -0400
Subject: [PATCH] guest: add convert_to_vnc()
From: Cole Robinson <crobinso@redhat.com>
This is the beginnings of support for a `virt-xml --convert-to-vnc`
option. Take an existing VM, strip out most of the previous graphics
config, and add VNC graphics.
We try to convert over some of the shared graphic bits, like listen
and port settings, if they were previously specified.
If spice GL was enabled, we convert to egl-headless config
Signed-off-by: Cole Robinson <crobinso@redhat.com>
(cherry picked from commit 229b905053f3d4bc17e7ad0f8d3fc2c3f23c47cd)
Conflicts:
tests/test_xmlparse.py
virtinst/guest.py
https://issues.redhat.com/browse/RHEL-17435
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
.../data/xmlparse/convert-to-vnc-empty-in.xml | 13 +++
.../xmlparse/convert-to-vnc-empty-out.xml | 13 +++
.../xmlparse/convert-to-vnc-has-vnc-in.xml | 31 +++++++
.../xmlparse/convert-to-vnc-has-vnc-out.xml | 22 +++++
.../convert-to-vnc-spice-devices-in.xml | 30 +++++++
.../convert-to-vnc-spice-devices-out.xml | 22 +++++
.../convert-to-vnc-spice-manyopts-in.xml | 20 +++++
.../convert-to-vnc-spice-manyopts-out.xml | 20 +++++
tests/test_xmlparse.py | 14 +++
virtinst/guest.py | 88 ++++++++++++++++++-
10 files changed, 269 insertions(+), 4 deletions(-)
create mode 100644 tests/data/xmlparse/convert-to-vnc-empty-in.xml
create mode 100644 tests/data/xmlparse/convert-to-vnc-empty-out.xml
create mode 100644 tests/data/xmlparse/convert-to-vnc-has-vnc-in.xml
create mode 100644 tests/data/xmlparse/convert-to-vnc-has-vnc-out.xml
create mode 100644 tests/data/xmlparse/convert-to-vnc-spice-devices-in.xml
create mode 100644 tests/data/xmlparse/convert-to-vnc-spice-devices-out.xml
create mode 100644 tests/data/xmlparse/convert-to-vnc-spice-manyopts-in.xml
create mode 100644 tests/data/xmlparse/convert-to-vnc-spice-manyopts-out.xml
diff --git a/tests/data/xmlparse/convert-to-vnc-empty-in.xml b/tests/data/xmlparse/convert-to-vnc-empty-in.xml
new file mode 100644
index 000000000..bc370a8a2
--- /dev/null
+++ b/tests/data/xmlparse/convert-to-vnc-empty-in.xml
@@ -0,0 +1,13 @@
+<domain type='qemu'>
+ <name>convert-me</name>
+ <memory unit='KiB'>8388608</memory>
+ <currentMemory unit='KiB'>2097152</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='i686'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <devices>
+ </devices>
+</domain>
+
diff --git a/tests/data/xmlparse/convert-to-vnc-empty-out.xml b/tests/data/xmlparse/convert-to-vnc-empty-out.xml
new file mode 100644
index 000000000..8612a6567
--- /dev/null
+++ b/tests/data/xmlparse/convert-to-vnc-empty-out.xml
@@ -0,0 +1,13 @@
+<domain type="qemu">
+ <name>convert-me</name>
+ <memory unit="KiB">8388608</memory>
+ <currentMemory unit="KiB">2097152</currentMemory>
+ <vcpu placement="static">2</vcpu>
+ <os>
+ <type arch="i686">hvm</type>
+ <boot dev="hd"/>
+ </os>
+ <devices>
+ <graphics type="vnc" port="-1"/>
+ </devices>
+</domain>
diff --git a/tests/data/xmlparse/convert-to-vnc-has-vnc-in.xml b/tests/data/xmlparse/convert-to-vnc-has-vnc-in.xml
new file mode 100644
index 000000000..29ee53d4c
--- /dev/null
+++ b/tests/data/xmlparse/convert-to-vnc-has-vnc-in.xml
@@ -0,0 +1,31 @@
+<domain type="kvm">
+ <name>convert-me</name>
+ <memory>2097152</memory>
+ <currentMemory>2097152</currentMemory>
+ <vcpu>2</vcpu>
+ <os>
+ <type arch="x86_64" machine="q35">hvm</type>
+ <boot dev="network"/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state="off"/>
+ </features>
+ <devices>
+ <channel type="spicevmc">
+ <target type="virtio" name="com.redhat.spice.0"/>
+ </channel>
+ <graphics type="spice" port="-1" tlsPort="-1" autoport="yes">
+ <image compression="off"/>
+ </graphics>
+ <graphics type="vnc" port="5907"/>
+ <sound model="ich9"/>
+ <audio type='spice'/>
+ <video>
+ <model type="virtio"/>
+ </video>
+ <redirdev bus="usb" type="spicevmc"/>
+ <redirdev bus="usb" type="spicevmc"/>
+ </devices>
+</domain>
diff --git a/tests/data/xmlparse/convert-to-vnc-has-vnc-out.xml b/tests/data/xmlparse/convert-to-vnc-has-vnc-out.xml
new file mode 100644
index 000000000..113f70a1e
--- /dev/null
+++ b/tests/data/xmlparse/convert-to-vnc-has-vnc-out.xml
@@ -0,0 +1,22 @@
+<domain type="kvm">
+ <name>convert-me</name>
+ <memory>2097152</memory>
+ <currentMemory>2097152</currentMemory>
+ <vcpu>2</vcpu>
+ <os>
+ <type arch="x86_64" machine="q35">hvm</type>
+ <boot dev="network"/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state="off"/>
+ </features>
+ <devices>
+ <graphics type="vnc" port="5907"/>
+ <sound model="ich9"/>
+ <video>
+ <model type="virtio"/>
+ </video>
+ </devices>
+</domain>
diff --git a/tests/data/xmlparse/convert-to-vnc-spice-devices-in.xml b/tests/data/xmlparse/convert-to-vnc-spice-devices-in.xml
new file mode 100644
index 000000000..8c5c63bdf
--- /dev/null
+++ b/tests/data/xmlparse/convert-to-vnc-spice-devices-in.xml
@@ -0,0 +1,30 @@
+<domain type="kvm">
+ <name>convert-me</name>
+ <memory>2097152</memory>
+ <currentMemory>2097152</currentMemory>
+ <vcpu>2</vcpu>
+ <os>
+ <type arch="x86_64" machine="q35">hvm</type>
+ <boot dev="network"/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state="off"/>
+ </features>
+ <devices>
+ <channel type="spicevmc">
+ <target type="virtio" name="com.redhat.spice.0"/>
+ </channel>
+ <graphics type="spice" port="-1" tlsPort="-1" autoport="yes">
+ <image compression="off"/>
+ </graphics>
+ <sound model="ich9"/>
+ <audio type='spice'/>
+ <video>
+ <model type="virtio"/>
+ </video>
+ <redirdev bus="usb" type="spicevmc"/>
+ <redirdev bus="usb" type="spicevmc"/>
+ </devices>
+</domain>
diff --git a/tests/data/xmlparse/convert-to-vnc-spice-devices-out.xml b/tests/data/xmlparse/convert-to-vnc-spice-devices-out.xml
new file mode 100644
index 000000000..cc3fefabe
--- /dev/null
+++ b/tests/data/xmlparse/convert-to-vnc-spice-devices-out.xml
@@ -0,0 +1,22 @@
+<domain type="kvm">
+ <name>convert-me</name>
+ <memory>2097152</memory>
+ <currentMemory>2097152</currentMemory>
+ <vcpu>2</vcpu>
+ <os>
+ <type arch="x86_64" machine="q35">hvm</type>
+ <boot dev="network"/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state="off"/>
+ </features>
+ <devices>
+ <graphics type="vnc" port="-1"/>
+ <sound model="ich9"/>
+ <video>
+ <model type="virtio"/>
+ </video>
+ </devices>
+</domain>
diff --git a/tests/data/xmlparse/convert-to-vnc-spice-manyopts-in.xml b/tests/data/xmlparse/convert-to-vnc-spice-manyopts-in.xml
new file mode 100644
index 000000000..ebd20a56d
--- /dev/null
+++ b/tests/data/xmlparse/convert-to-vnc-spice-manyopts-in.xml
@@ -0,0 +1,20 @@
+<domain type='qemu'>
+ <name>convert-me</name>
+ <memory unit='KiB'>8388608</memory>
+ <currentMemory unit='KiB'>2097152</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='i686'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <devices>
+ <graphics type='spice' port='5907' tlsPort='5901' autoport='no' passwd='sercet' passwdValidTo='2011-05-31T16:11:22' connected='disconnect' keymap='de' listen='127.0.0.1'>
+ <listen type='socket' socket='/tmp/spice.sock'/>
+ <listen type='address' address='127.0.0.1'/>
+ <gl enable='yes' rendernode='/dev/my/rendernode'/>
+ </graphics>
+ <graphics type='sdl'/>
+ </devices>
+</domain>
+
diff --git a/tests/data/xmlparse/convert-to-vnc-spice-manyopts-out.xml b/tests/data/xmlparse/convert-to-vnc-spice-manyopts-out.xml
new file mode 100644
index 000000000..c98c63830
--- /dev/null
+++ b/tests/data/xmlparse/convert-to-vnc-spice-manyopts-out.xml
@@ -0,0 +1,20 @@
+<domain type="qemu">
+ <name>convert-me</name>
+ <memory unit="KiB">8388608</memory>
+ <currentMemory unit="KiB">2097152</currentMemory>
+ <vcpu placement="static">2</vcpu>
+ <os>
+ <type arch="i686">hvm</type>
+ <boot dev="hd"/>
+ </os>
+ <clock offset="utc"/>
+ <devices>
+ <graphics type="vnc" port="5907" keymap="de" listen="127.0.0.1" passwd="sercet" passwdValidTo="2011-05-31T16:11:22">
+ <listen type="socket" socket="/tmp/spice.sock"/>
+ <listen type="address" address="127.0.0.1"/>
+ </graphics>
+ <graphics type="egl-headless">
+ <gl rendernode="/dev/my/rendernode"/>
+ </graphics>
+ </devices>
+</domain>
diff --git a/tests/test_xmlparse.py b/tests/test_xmlparse.py
index ac2fb38d2..e11d15d07 100644
--- a/tests/test_xmlparse.py
+++ b/tests/test_xmlparse.py
@@ -1135,3 +1135,17 @@ def testControllerAttachedDevices():
# Little test for DeviceAddress.pretty_desc
assert devs[-1].address.pretty_desc() == "0:0:0:3"
+
+
+def testConvertToVNC():
+ conn = utils.URIs.openconn(utils.URIs.kvm_x86)
+
+ def _test(filename_base):
+ guest, outfile = _get_test_content(conn, filename_base)
+ guest.convert_to_vnc()
+ _alter_compare(conn, guest.get_xml(), outfile)
+
+ _test("convert-to-vnc-empty")
+ _test("convert-to-vnc-spice-devices")
+ _test("convert-to-vnc-spice-manyopts")
+ _test("convert-to-vnc-has-vnc")
diff --git a/virtinst/guest.py b/virtinst/guest.py
index 7aa62be49..93e71a149 100644
--- a/virtinst/guest.py
+++ b/virtinst/guest.py
@@ -706,6 +706,84 @@ class Guest(XMLBuilder):
self.vcpus = self.cpu.vcpus_from_topology()
self.cpu.set_topology_defaults(self.vcpus)
+ def _convert_spice_gl_to_egl_headless(self):
+ if not self.has_spice():
+ return
+
+ spicedev = [g for g in self.devices.graphics if g.type == "spice"][0]
+ if not spicedev.gl:
+ return
+
+ dev = DeviceGraphics(self.conn)
+ dev.type = "egl-headless"
+ dev.set_defaults(self.conn)
+ if spicedev.rendernode:
+ dev.rendernode = spicedev.rendernode
+ self.add_device(dev)
+
+ def _convert_to_vnc_graphics(self):
+ """
+ If there's already VNC graphics configured, we leave it intact,
+ but rip out all evidence of other graphics devices.
+
+ If there's other non-VNC, non-egl-headless configured, we try to
+ inplace convert the first device we encounter.
+
+ If there's no graphics configured, set up a default VNC config.`
+ """
+ vnc_devs = [g for g in self.devices.graphics if g.type == "vnc"]
+ # We ignore egl-headless, it's not a true graphical frontend
+ other_devs = [g for g in self.devices.graphics if
+ g.type != "vnc" and g.type != "egl-headless"]
+
+ # Guest already had a vnc device.
+ # Remove all other devs and we are done
+ if vnc_devs:
+ for g in other_devs:
+ self.remove_device(g)
+ return
+
+ # We didn't find any non-vnc device to convert.
+ # Add a vnc device with default config
+ if not other_devs:
+ dev = DeviceGraphics(self.conn)
+ dev.type = dev.TYPE_VNC
+ dev.set_defaults(self.conn)
+ self.add_device(dev)
+ return
+
+ # Convert the pre-existing graphics device to vnc
+ # Remove the rest
+ dev = other_devs.pop(0)
+ srcdev = DeviceGraphics(self.conn, dev.get_xml())
+ for g in other_devs:
+ self.remove_device(g)
+
+ dev.clear()
+ dev.type = dev.TYPE_VNC
+ dev.keymap = srcdev.keymap
+ dev.port = srcdev.port
+ dev.autoport = srcdev.autoport
+ dev.passwd = srcdev.passwd
+ dev.passwdValidTo = srcdev.passwdValidTo
+ dev.listen = srcdev.listen
+ for listen in srcdev.listens:
+ srcdev.remove_child(listen)
+ dev.add_child(listen)
+ dev.set_defaults(self)
+
+ def convert_to_vnc(self):
+ """
+ Convert existing XML to have one VNC graphics connection.
+ """
+ self._convert_spice_gl_to_egl_headless()
+
+ # Rip out spice graphics devices unconditionally.
+ # Could be necessary if XML is in broken state.
+ self._force_remove_spice_devices()
+
+ self._convert_to_vnc_graphics()
+
def set_defaults(self, _guest):
self.set_capabilities_defaults()
@@ -1061,10 +1139,12 @@ class Guest(XMLBuilder):
if redirdev.type == "spicevmc":
self.devices.remove_child(redirdev)
- def _remove_spice_devices(self, rmdev):
- if rmdev.DEVICE_TYPE != "graphics" or self.has_spice():
- return
-
+ def _force_remove_spice_devices(self):
self._remove_spice_audio()
self._remove_spice_channels()
self._remove_spice_usbredir()
+
+ def _remove_spice_devices(self, rmdev):
+ if rmdev.DEVICE_TYPE != "graphics" or self.has_spice():
+ return
+ self._force_remove_spice_devices()
--
2.48.1