[libvirt PATCH v2 0/3] qemu: add support for VNC power control options

Daniel P. Berrang=C3=A9 (3): conf: add support for VNC power control setting qemu: probe for -vnc power-control option support qemu: wire up support for VNC power control options docs/formatdomain.rst | 5 +++ docs/schemas/domaincommon.rng | 5 +++ src/conf/domain_conf.c | 15 +++++++ src/conf/domain_conf.h | 1 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 6 +++ src/qemu/qemu_validate.c | 21 ++++++++++ .../caps_6.0.0.x86_64.xml | 1 + .../graphics-vnc-power.x86_64-latest.args | 40 +++++++++++++++++++ tests/qemuxml2argvdata/graphics-vnc-power.xml | 36 +++++++++++++++++ tests/qemuxml2argvtest.c | 1 + 12 files changed, 134 insertions(+) create mode 100644 tests/qemuxml2argvdata/graphics-vnc-power.x86_64-latest.a= rgs create mode 100644 tests/qemuxml2argvdata/graphics-vnc-power.xml --=20 2.29.2

The <graphics type="vnc" .... powerControl="yes"/> option instructs the VNC server to enable an extension that lets the client perform a graceful shutdown, reboot and hard reset. This is enabled by default since it cannot be assumed that the VNC client user has administrator rights over the guest OS. In the case where the VNC user is a guest administrator though, it is reasonable to allow direct power control host side too. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- docs/formatdomain.rst | 5 +++++ docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 15 +++++++++++++++ src/conf/domain_conf.h | 1 + 4 files changed, 26 insertions(+) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index eafd6b3396..580319365c 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -5791,6 +5791,11 @@ interaction with the admin. ``autoport`` having no effect due to security reasons) :since:`Since 1.0.6` . + For VNC, the ``powerControl`` attribute can be used to enable VM shutdown, + reboot and reset power control features for the VNC client. This is + appropriate if the authenticated VNC client user already has administrator + privileges in the guest :since:`Since 7.1.0`. + Although VNC doesn't support OpenGL natively, it can be paired with graphics type ``egl-headless`` (see below) which will instruct QEMU to open and use drm nodes for OpenGL rendering. diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index e6de934456..49dc4b5130 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3663,6 +3663,11 @@ </choice> </attribute> </optional> + <optional> + <attribute name="powerControl"> + <ref name="virYesNo"/> + </attribute> + </optional> </group> <group> <optional> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b731744f04..5e15d394c4 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -13150,6 +13150,7 @@ virDomainGraphicsDefParseXMLVNC(virDomainGraphicsDefPtr def, g_autofree char *websocketGenerated = virXMLPropString(node, "websocketGenerated"); g_autofree char *sharePolicy = virXMLPropString(node, "sharePolicy"); g_autofree char *autoport = virXMLPropString(node, "autoport"); + g_autofree char *powerControl = virXMLPropString(node, "powerControl"); if (virDomainGraphicsListensParseXML(def, node, ctxt, flags) < 0) return -1; @@ -13206,6 +13207,16 @@ virDomainGraphicsDefParseXMLVNC(virDomainGraphicsDefPtr def, } } + if (powerControl) { + int powerControlVal = virTristateBoolTypeFromString(powerControl); + if (powerControlVal < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse vnc power control '%s'"), powerControl); + return -1; + } + def->data.vnc.powerControl = powerControlVal; + } + def->data.vnc.keymap = virXMLPropString(node, "keymap"); if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth, @@ -27148,6 +27159,10 @@ virDomainGraphicsDefFormat(virBufferPtr buf, virDomainGraphicsVNCSharePolicyTypeToString( def->data.vnc.sharePolicy)); + if (def->data.vnc.powerControl) + virBufferAsprintf(buf, " powerControl='%s'", + virTristateBoolTypeToString(def->data.vnc.powerControl)); + virDomainGraphicsAuthDefFormatAttr(buf, &def->data.vnc.auth, flags); break; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 930eed60de..881d64bae9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1712,6 +1712,7 @@ struct _virDomainGraphicsDef { char *keymap; virDomainGraphicsAuthDef auth; int sharePolicy; + virTristateBool powerControl; } vnc; struct { char *display; -- 2.29.2

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml | 1 + 3 files changed, 4 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 3f8593a9e5..8fa23f14be 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -617,6 +617,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "cpu-max", "memory-backend-file.x-use-canonical-path-for-ramblock-id", "vnc-opts", + "vnc-power-control", ); @@ -3297,6 +3298,7 @@ static struct virQEMUCapsCommandLineProps virQEMUCapsCommandLine[] = { { "fw_cfg", "file", QEMU_CAPS_FW_CFG }, { "fsdev", "fmode", QEMU_CAPS_FSDEV_CREATEMODE }, /* Could have also checked fsdev->dmode */ { "vnc", "display", QEMU_CAPS_VNC_OPTS }, + { "vnc", "power-control", QEMU_CAPS_VNC_POWER_CONTROL }, }; static int diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 38574eef16..e327db0148 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -597,6 +597,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_CPU_MAX, /* -cpu max */ QEMU_CAPS_X_USE_CANONICAL_PATH_FOR_RAMBLOCK_ID, /* -object memory-backend-file,x-use-canonical-path-for-ramblock-id= */ QEMU_CAPS_VNC_OPTS, /* -vnc uses QemuOpts parser instead of custom code */ + QEMU_CAPS_VNC_POWER_CONTROL, /* -vnc power-control option */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml index 23fb5b7393..3ef05ec94e 100644 --- a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml @@ -256,6 +256,7 @@ <flag name='cpu-max'/> <flag name='memory-backend-file.x-use-canonical-path-for-ramblock-id'/> <flag name='vnc-opts'/> + <flag name='vnc-power-control'/> <version>5002050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100242</microcodeVersion> -- 2.29.2

This allows the VNC client user to perform a shutdown, reboot and reset of the VM from the host side. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_command.c | 6 +++ src/qemu/qemu_validate.c | 21 ++++++++++ .../graphics-vnc-power.x86_64-latest.args | 40 +++++++++++++++++++ tests/qemuxml2argvdata/graphics-vnc-power.xml | 36 +++++++++++++++++ tests/qemuxml2argvtest.c | 1 + 5 files changed, 104 insertions(+) create mode 100644 tests/qemuxml2argvdata/graphics-vnc-power.x86_64-latest.args create mode 100644 tests/qemuxml2argvdata/graphics-vnc-power.xml diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index d801018aa2..7597ffafd1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7700,6 +7700,12 @@ qemuBuildGraphicsVNCCommandLine(virQEMUDriverConfigPtr cfg, /* TODO: Support ACLs later */ } + if (graphics->data.vnc.powerControl != VIR_TRISTATE_BOOL_ABSENT) { + virBufferAsprintf(&opt, ",power-control=%s", + graphics->data.vnc.powerControl == VIR_TRISTATE_BOOL_YES ? + "on" : "off"); + } + virCommandAddArg(cmd, "-vnc"); virCommandAddArgBuffer(cmd, &opt); if (graphics->data.vnc.keymap) diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 2541ae856a..2f98209470 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -3939,7 +3939,22 @@ qemuValidateDomainDeviceDefSPICEGraphics(const virDomainGraphicsDef *graphics, return 0; } +static int +qemuValidateDomainDeviceDefVNCGraphics(const virDomainGraphicsDef *graphics, + virQEMUDriverPtr driver, + virQEMUCapsPtr qemuCaps) +{ + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + + if (graphics->data.vnc.powerControl != VIR_TRISTATE_BOOL_ABSENT && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC_POWER_CONTROL)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("VNC power control is not available")); + return -1; + } + return 0; +} static int qemuValidateDomainDeviceDefGraphics(const virDomainGraphicsDef *graphics, const virDomainDef *def, @@ -4023,6 +4038,12 @@ qemuValidateDomainDeviceDefGraphics(const virDomainGraphicsDef *graphics, break; case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + if (qemuValidateDomainDeviceDefVNCGraphics(graphics, driver, + qemuCaps) < 0) + return -1; + + break; + case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_LAST: diff --git a/tests/qemuxml2argvdata/graphics-vnc-power.x86_64-latest.args b/tests/qemuxml2argvdata/graphics-vnc-power.x86_64-latest.args new file mode 100644 index 0000000000..7ef6f7f4e6 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-vnc-power.x86_64-latest.args @@ -0,0 +1,40 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i386 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,\ +file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-machine pc,accel=tcg,usb=off,dump-guest-core=off,memory-backend=pc.ram \ +-cpu qemu64 \ +-m 214 \ +-object memory-backend-ram,id=pc.ram,size=224395264 \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 \ +-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1",\ +"node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-1-format","read-only":false,"driver":"raw",\ +"file":"libvirt-1-storage"}' \ +-device ide-hd,bus=ide.0,unit=0,drive=libvirt-1-format,id=ide0-0-0,bootindex=1 \ +-vnc '[::]:59630,power-control=on' \ +-device cirrus-vga,id=video0,bus=pci.0,addr=0x2 \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\ +resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/graphics-vnc-power.xml b/tests/qemuxml2argvdata/graphics-vnc-power.xml new file mode 100644 index 0000000000..00f0a215a5 --- /dev/null +++ b/tests/qemuxml2argvdata/graphics-vnc-power.xml @@ -0,0 +1,36 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-i386</emulator> + <disk type='block' device='disk'> + <driver name='qemu' type='raw'/> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='vnc' port='65530' autoport='no' listen='::' powerControl='yes'> + <listen type='address' address='::'/> + </graphics> + <video> + <model type='cirrus' vram='16384' heads='1'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index db438c5466..682b7d52d2 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1365,6 +1365,7 @@ mymain(void) QEMU_CAPS_DEVICE_CIRRUS_VGA); DO_TEST("graphics-vnc-policy", QEMU_CAPS_VNC, QEMU_CAPS_DEVICE_CIRRUS_VGA); + DO_TEST_CAPS_LATEST("graphics-vnc-power"); DO_TEST("graphics-vnc-no-listen-attr", QEMU_CAPS_VNC, QEMU_CAPS_DEVICE_CIRRUS_VGA); DO_TEST("graphics-vnc-remove-generated-socket", QEMU_CAPS_VNC, -- 2.29.2

On Tue, Feb 16, 2021 at 18:10:31 +0000, Daniel Berrange wrote:
This allows the VNC client user to perform a shutdown, reboot and reset of the VM from the host side.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_command.c | 6 +++ src/qemu/qemu_validate.c | 21 ++++++++++ .../graphics-vnc-power.x86_64-latest.args | 40 +++++++++++++++++++ tests/qemuxml2argvdata/graphics-vnc-power.xml | 36 +++++++++++++++++ tests/qemuxml2argvtest.c | 1 + 5 files changed, 104 insertions(+) create mode 100644 tests/qemuxml2argvdata/graphics-vnc-power.x86_64-latest.args create mode 100644 tests/qemuxml2argvdata/graphics-vnc-power.xml
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index d801018aa2..7597ffafd1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7700,6 +7700,12 @@ qemuBuildGraphicsVNCCommandLine(virQEMUDriverConfigPtr cfg, /* TODO: Support ACLs later */ }
+ if (graphics->data.vnc.powerControl != VIR_TRISTATE_BOOL_ABSENT) { + virBufferAsprintf(&opt, ",power-control=%s", + graphics->data.vnc.powerControl == VIR_TRISTATE_BOOL_YES ? + "on" : "off"); + } + virCommandAddArg(cmd, "-vnc"); virCommandAddArgBuffer(cmd, &opt); if (graphics->data.vnc.keymap) diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 2541ae856a..2f98209470 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -3939,7 +3939,22 @@ qemuValidateDomainDeviceDefSPICEGraphics(const virDomainGraphicsDef *graphics, return 0; }
+static int
Two empty lines between functions please.
+qemuValidateDomainDeviceDefVNCGraphics(const virDomainGraphicsDef *graphics, + virQEMUDriverPtr driver, + virQEMUCapsPtr qemuCaps) +{ + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
clang says: ../../../libvirt/src/qemu/qemu_validate.c:3947:36: error: unused variable 'cfg' [-Werror,-Wunused-variable] g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); ^ 1 error generated.
+ + if (graphics->data.vnc.powerControl != VIR_TRISTATE_BOOL_ABSENT && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC_POWER_CONTROL)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("VNC power control is not available")); + return -1; + }
+ return 0; +} static int
Here too.
qemuValidateDomainDeviceDefGraphics(const virDomainGraphicsDef *graphics, const virDomainDef *def, @@ -4023,6 +4038,12 @@ qemuValidateDomainDeviceDefGraphics(const virDomainGraphicsDef *graphics, break;
case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + if (qemuValidateDomainDeviceDefVNCGraphics(graphics, driver, + qemuCaps) < 0) + return -1; + + break; + case VIR_DOMAIN_GRAPHICS_TYPE_RDP: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_LAST:

On Tue, Feb 16, 2021 at 18:10:28 +0000, Daniel Berrange wrote:
Daniel P. Berrang=C3=A9 (3):
Is the broken encoding related to the list brokenness?
conf: add support for VNC power control setting qemu: probe for -vnc power-control option support qemu: wire up support for VNC power control options
Series: Peter Krempa <pkrempa@redhat.com> if you fix the issues in 3/3

On Tue, Feb 16, 2021 at 08:58:36PM +0100, Peter Krempa wrote:
On Tue, Feb 16, 2021 at 18:10:28 +0000, Daniel Berrange wrote:
Daniel P. Berrang=C3=A9 (3):
Is the broken encoding related to the list brokenness?
No, git-publish decided todo this for reasons I don't understand
conf: add support for VNC power control setting qemu: probe for -vnc power-control option support qemu: wire up support for VNC power control options
Series:
Peter Krempa <pkrempa@redhat.com>
if you fix the issues in 3/3
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
participants (2)
-
Daniel P. Berrangé
-
Peter Krempa