[PATCH RFC 0/6] Add qemu-vnc support
From: Marc-André Lureau <marcandre.lureau@redhat.com> Hi, This series allows to run the QEMU VNC server in a standalone process. The qemu-vnc binary is aimed to be released with QEMU 11.1. It is still being reviewed (https://patchew.org/QEMU/20260410-qemu-vnc-v2-0-231416f76dc3@redhat.com/) The standalone VNC activates automatically when a domain has both <graphics type='dbus'/> (bus mode) and <graphics type='vnc'/>, and the qemu-vnc binary is available. Comments welcome! Marc-André Lureau (6): qemu: add standalone VNC state directory qemu: add qemu-vnc configuration qemu: add qemu-vnc helper unit qemu: integrate standalone VNC in domain lifecycle qemu: wire up standalone VNC in driver APIs qemu: add tests for standalone VNC graphics po/POTFILES | 1 + src/qemu/libvirtd_qemu.aug | 1 + src/qemu/meson.build | 1 + src/qemu/qemu.conf.in | 8 + src/qemu/qemu_command.c | 2 + src/qemu/qemu_conf.c | 8 + src/qemu/qemu_conf.h | 2 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 68 ++- src/qemu/qemu_extdevice.c | 13 +- src/qemu/qemu_hotplug.c | 12 + src/qemu/qemu_process.c | 40 +- src/qemu/qemu_vnc.c | 407 ++++++++++++++++++ src/qemu/qemu_vnc.h | 41 ++ src/qemu/test_libvirtd_qemu.aug.in | 1 + ...hics-vnc-standalone-p2p.x86_64-latest.args | 34 ++ ...phics-vnc-standalone-p2p.x86_64-latest.xml | 40 ++ .../graphics-vnc-standalone-p2p.xml | 39 ++ ...s-vnc-standalone-socket.x86_64-latest.args | 33 ++ ...cs-vnc-standalone-socket.x86_64-latest.xml | 40 ++ .../graphics-vnc-standalone-socket.xml | 40 ++ ...graphics-vnc-standalone.x86_64-latest.args | 33 ++ .../graphics-vnc-standalone.x86_64-latest.xml | 40 ++ .../graphics-vnc-standalone.xml | 40 ++ tests/qemuxmlconftest.c | 4 + tests/testutilsqemu.c | 9 + 27 files changed, 950 insertions(+), 10 deletions(-) create mode 100644 src/qemu/qemu_vnc.c create mode 100644 src/qemu/qemu_vnc.h create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-socket.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone.xml -- 2.53.0
From: Marc-André Lureau <marcandre.lureau@redhat.com> Add a state directory for the standalone qemu-vnc process, following the same pattern used for the RDP state directory. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_conf.c | 2 ++ src/qemu/qemu_conf.h | 1 + src/qemu/qemu_driver.c | 12 ++++++++++++ 3 files changed, 15 insertions(+) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index f2f9cc8a21..724617ee8b 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -242,6 +242,7 @@ virQEMUDriverConfig *virQEMUDriverConfigNew(bool privileged, cfg->autostartDir = g_strdup_printf("%s/qemu/autostart", cfg->configBaseDir); cfg->slirpStateDir = g_strdup_printf("%s/slirp", cfg->stateDir); cfg->rdpStateDir = g_strdup_printf("%s/rdp", cfg->stateDir); + cfg->vncStateDir = g_strdup_printf("%s/vnc", cfg->stateDir); cfg->passtStateDir = g_strdup_printf("%s/passt", cfg->stateDir); cfg->dbusStateDir = g_strdup_printf("%s/dbus", cfg->stateDir); @@ -368,6 +369,7 @@ static void virQEMUDriverConfigDispose(void *obj) g_free(cfg->passtStateDir); g_free(cfg->dbusStateDir); g_free(cfg->rdpStateDir); + g_free(cfg->vncStateDir); g_free(cfg->libDir); g_free(cfg->cacheDir); diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 511ab77f71..d558f3ab19 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -112,6 +112,7 @@ struct _virQEMUDriverConfig { char *passtStateDir; char *dbusStateDir; char *rdpStateDir; + char *vncStateDir; /* These two directories are ones QEMU processes use (so must match * the QEMU user/group */ char *libDir; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d227ac58cd..83d0bab126 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -658,6 +658,11 @@ qemuStateInitialize(bool privileged, cfg->rdpStateDir); goto error; } + if (g_mkdir_with_parents(cfg->vncStateDir, 0777) < 0) { + virReportSystemError(errno, _("Failed to create vnc state dir %1$s"), + cfg->vncStateDir); + goto error; + } qemu_driver->inhibitor = virInhibitorNew( VIR_INHIBITOR_WHAT_SHUTDOWN, @@ -830,6 +835,13 @@ qemuStateInitialize(bool privileged, (int)cfg->group); goto error; } + if (chown(cfg->vncStateDir, cfg->user, cfg->group) < 0) { + virReportSystemError(errno, + _("unable to set ownership of '%1$s' to %2$d:%3$d"), + cfg->vncStateDir, (int)cfg->user, + (int)cfg->group); + goto error; + } run_uid = cfg->user; run_gid = cfg->group; -- 2.53.0
From: Marc-André Lureau <marcandre.lureau@redhat.com> Add qemu_vnc configuration entry to specify the path to the standalone qemu-vnc binary. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/libvirtd_qemu.aug | 1 + src/qemu/qemu.conf.in | 8 ++++++++ src/qemu/qemu_conf.c | 6 ++++++ src/qemu/qemu_conf.h | 1 + src/qemu/test_libvirtd_qemu.aug.in | 1 + 5 files changed, 17 insertions(+) diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index eb790d48be..311992e441 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -123,6 +123,7 @@ module Libvirtd_qemu = | str_entry "pr_helper" | str_entry "slirp_helper" | str_entry "qemu_rdp" + | str_entry "qemu_vnc" | str_entry "dbus_daemon" | bool_entry "set_process_name" | int_entry "max_processes" diff --git a/src/qemu/qemu.conf.in b/src/qemu/qemu.conf.in index 5eacd70022..97b0141cf6 100644 --- a/src/qemu/qemu.conf.in +++ b/src/qemu/qemu.conf.in @@ -1094,6 +1094,14 @@ #qemu_rdp = "qemu-rdp" +# Path to the standalone qemu-vnc VNC server. +# When available and both <graphics type='dbus'/> and <graphics type='vnc'/> +# are configured, libvirt will use qemu-vnc instead of QEMU's built-in VNC. +# If this is not an absolute path, the program will be searched for +# in $PATH. +#qemu_vnc = "qemu-vnc" + + # Path to the dbus-daemon # If this is not an absolute path, the program will be searched for # in $PATH. diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 724617ee8b..6981edda18 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -116,6 +116,7 @@ VIR_ONCE_GLOBAL_INIT(virQEMUConfig); #define QEMU_BRIDGE_HELPER "qemu-bridge-helper" #define QEMU_PR_HELPER "qemu-pr-helper" #define QEMU_RDP "qemu-rdp" +#define QEMU_VNC "qemu-vnc" #define QEMU_DBUS_DAEMON "dbus-daemon" @@ -290,6 +291,7 @@ virQEMUDriverConfig *virQEMUDriverConfigNew(bool privileged, cfg->slirpHelperName = g_strdup(QEMU_SLIRP_HELPER); cfg->dbusDaemonName = g_strdup(QEMU_DBUS_DAEMON); cfg->qemuRdpName = g_strdup(QEMU_RDP); + cfg->qemuVncName = g_strdup(QEMU_VNC); cfg->securityDefaultConfined = true; cfg->securityRequireConfined = false; @@ -421,6 +423,7 @@ static void virQEMUDriverConfigDispose(void *obj) g_free(cfg->slirpHelperName); g_free(cfg->dbusDaemonName); g_free(cfg->qemuRdpName); + g_free(cfg->qemuVncName); g_free(cfg->autoDumpPath); @@ -858,6 +861,9 @@ virQEMUDriverConfigLoadProcessEntry(virQEMUDriverConfig *cfg, if (virConfGetValueString(conf, "qemu_rdp", &cfg->qemuRdpName) < 0) return -1; + if (virConfGetValueString(conf, "qemu_vnc", &cfg->qemuVncName) < 0) + return -1; + if (virConfGetValueBool(conf, "set_process_name", &cfg->setProcessName) < 0) return -1; if (virConfGetValueUInt(conf, "max_processes", &cfg->maxProcesses) < 0) diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index d558f3ab19..5ea1b28f3e 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -199,6 +199,7 @@ struct _virQEMUDriverConfig { char *slirpHelperName; char *dbusDaemonName; char *qemuRdpName; + char *qemuVncName; bool macFilter; diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index 2582c6a09c..c4cf9cf634 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -129,6 +129,7 @@ module Test_libvirtd_qemu = { "pr_helper" = "qemu-pr-helper" } { "slirp_helper" = "/usr/bin/slirp-helper" } { "qemu_rdp" = "qemu-rdp" } +{ "qemu_vnc" = "qemu-vnc" } { "dbus_daemon" = "dbus-daemon" } { "swtpm_user" = "tss" } { "swtpm_group" = "tss" } -- 2.53.0
From: Marc-André Lureau <marcandre.lureau@redhat.com> Add helpers to manage the standalone qemu-vnc VNC server process. The qemu-vnc server connects to QEMU via the D-Bus display interface, providing VNC access decoupled from the QEMU process. The helper handles process lifecycle (start/stop), D-Bus name watching, and provides D-Bus methods for password management, certificate reloading, and client connections. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- po/POTFILES | 1 + src/qemu/meson.build | 1 + src/qemu/qemu_vnc.c | 407 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_vnc.h | 41 +++++ 4 files changed, 450 insertions(+) create mode 100644 src/qemu/qemu_vnc.c create mode 100644 src/qemu/qemu_vnc.h diff --git a/po/POTFILES b/po/POTFILES index a5f8705eb8..a4e3ed6f25 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -208,6 +208,7 @@ src/qemu/qemu_validate.c src/qemu/qemu_vhost_user.c src/qemu/qemu_vhost_user_gpu.c src/qemu/qemu_virtiofs.c +src/qemu/qemu_vnc.c src/remote/libvirtd.policy.in src/remote/remote_daemon.c src/remote/remote_daemon_config.c diff --git a/src/qemu/meson.build b/src/qemu/meson.build index b4fb62f14f..9737e50734 100644 --- a/src/qemu/meson.build +++ b/src/qemu/meson.build @@ -43,6 +43,7 @@ qemu_driver_sources = [ 'qemu_vhost_user.c', 'qemu_vhost_user_gpu.c', 'qemu_virtiofs.c', + 'qemu_vnc.c', ] driver_source_files += files(qemu_driver_sources) diff --git a/src/qemu/qemu_vnc.c b/src/qemu/qemu_vnc.c new file mode 100644 index 0000000000..4afdf6aa79 --- /dev/null +++ b/src/qemu/qemu_vnc.c @@ -0,0 +1,407 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <config.h> + +#include <gio/gio.h> + +#include "qemu_dbus.h" +#include "qemu_extdevice.h" +#include "qemu_security.h" +#include "qemu_vnc.h" +#include "virerror.h" +#include "virlog.h" +#include "virpidfile.h" +#include "virgdbus.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("qemu.vnc"); + +#define ORG_QEMU_VNC "org.qemu.vnc" +#define ORG_QEMU_VNC_PATH "/org/qemu/Vnc1/Server" +#define ORG_QEMU_VNC_IFACE "org.qemu.Vnc1.Server" + + +void +qemuVncFree(qemuVnc *vnc) +{ + if (!vnc) + return; + + g_free(vnc); +} + + +qemuVnc * +qemuVncNew(void) +{ + g_autoptr(qemuVnc) vnc = g_new0(qemuVnc, 1); + + vnc->pid = -1; + + return g_steal_pointer(&vnc); +} + + +static char * +qemuVncCreatePidFilename(virDomainObj *vm) +{ + qemuDomainObjPrivate *priv = vm->privateData; + virQEMUDriver *driver = priv->driver; + g_autofree char *shortName = virDomainDefGetShortName(vm->def); + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + g_autofree char *name = NULL; + + name = g_strdup_printf("%s-vnc", shortName); + + return virPidFileBuildPath(cfg->vncStateDir, name); +} + + +void +qemuVncStop(virDomainObj *vm, virDomainGraphicsDef *gfx) +{ + qemuDomainObjPrivate *priv = vm->privateData; + qemuDomainGraphicsPrivate *gfxpriv = QEMU_DOMAIN_GRAPHICS_PRIVATE(gfx); + qemuVnc *vnc = gfxpriv->vnc; + g_autofree char *pidfile = qemuVncCreatePidFilename(vm); + virErrorPtr orig_err; + + if (!vnc) + return; + + if (vnc->leaving_id) { + g_dbus_connection_signal_unsubscribe(priv->dbusConnection, vnc->leaving_id); + vnc->leaving_id = 0; + } + g_clear_handle_id(&vnc->name_watch, g_bus_unwatch_name); + + virErrorPreserveLast(&orig_err); + + if (virPidFileForceCleanupPath(pidfile) < 0) { + VIR_WARN("Unable to kill qemu-vnc process"); + } else { + vnc->pid = -1; + } + + virErrorRestore(&orig_err); +} + + +int +qemuVncSetupCgroup(qemuVnc *vnc, + virCgroup *cgroup) +{ + return virCgroupAddProcess(cgroup, vnc->pid); +} + + +static void +on_leaving_signal(GDBusConnection *connection, + const gchar *sender_name G_GNUC_UNUSED, + const gchar *object_path G_GNUC_UNUSED, + const gchar *interface_name G_GNUC_UNUSED, + const gchar *signal_name G_GNUC_UNUSED, + GVariant *parameters, + gpointer user_data) +{ + qemuVnc *vnc = user_data; + const gchar *reason; + + g_variant_get(parameters, "(&s)", &reason); + VIR_DEBUG("%s.Leaving reason: '%s'", ORG_QEMU_VNC_IFACE, reason); + g_dbus_connection_signal_unsubscribe(connection, vnc->leaving_id); + vnc->leaving_id = 0; +} + + +static void +name_appeared_cb(GDBusConnection *connection, + const gchar *name G_GNUC_UNUSED, + const gchar *name_owner G_GNUC_UNUSED, + gpointer user_data) +{ + qemuVnc *vnc = user_data; + + VIR_DEBUG("'%s' appeared", name); + vnc->name_appeared = true; + + if (!vnc->leaving_id) { + vnc->leaving_id = g_dbus_connection_signal_subscribe( + connection, + ORG_QEMU_VNC, + ORG_QEMU_VNC_IFACE, + "Leaving", + ORG_QEMU_VNC_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + on_leaving_signal, + vnc, + NULL); + } +} + + +static void +name_vanished_cb(GDBusConnection *connection G_GNUC_UNUSED, + const gchar *name, + gpointer user_data) +{ + qemuVnc *vnc = user_data; + + if (vnc->name_appeared && vnc->leaving_id) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("'%1$s' vanished unexpectedly"), name); + } +} + + +int +qemuVncStart(virDomainObj *vm, virDomainGraphicsDef *gfx) +{ + qemuDomainObjPrivate *priv = vm->privateData; + virQEMUDriver *driver = priv->driver; + qemuDomainGraphicsPrivate *gfxpriv = QEMU_DOMAIN_GRAPHICS_PRIVATE(gfx); + qemuVnc *vnc = gfxpriv->vnc; + virDomainGraphicsListenDef *glisten = NULL; + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + g_autoptr(virCommand) cmd = NULL; + g_autofree char *shortName = virDomainDefGetShortName(vm->def); + g_autofree char *pidfile = NULL; + g_autofree char *logname = NULL; + g_autofree char *dbus_addr = qemuDBusGetAddress(driver, vm); + g_auto(virBuffer) vnc_addr = VIR_BUFFER_INITIALIZER; + pid_t pid = -1; + int logfd = -1; + g_autoptr(domainLogContext) logContext = NULL; + + if (vnc->pid != -1) { + return 0; + } + + if (!dbus_addr) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no D-Bus address")); + return -1; + } + + if (!(pidfile = qemuVncCreatePidFilename(vm))) + return -1; + + logname = g_strdup_printf("%s-qemu-vnc", shortName); + if (!(logContext = domainLogContextNew(cfg->stdioLogD, cfg->logDir, + QEMU_DRIVER_NAME, + vm, driver->privileged, + logname))) { + virLastErrorPrefixMessage("%s", _("can't open log context")); + return -1; + } + + logfd = domainLogContextGetWriteFD(logContext); + + cmd = virCommandNew(cfg->qemuVncName); + virCommandClearCaps(cmd); + virCommandSetPidFile(cmd, pidfile); + virCommandSetOutputFD(cmd, &logfd); + virCommandSetErrorFD(cmd, &logfd); + virCommandDaemonize(cmd); + virCommandAddArgPair(cmd, "--dbus-address", dbus_addr); + virCommandAddArgPair(cmd, "--bus-name", "org.qemu"); + virCommandAddArg(cmd, "--wait"); + + /* Build VNC listen address */ + if ((glisten = virDomainGraphicsGetListen(gfx, 0))) { + switch (glisten->type) { + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: + if (glisten->address) { + bool escapeAddr = strchr(glisten->address, ':') != NULL; + if (escapeAddr) + virBufferAsprintf(&vnc_addr, "[%s]", glisten->address); + else + virBufferAdd(&vnc_addr, glisten->address, -1); + } else { + virBufferAddLit(&vnc_addr, "localhost"); + } + virBufferAsprintf(&vnc_addr, ":%d", + gfx->data.vnc.port > 0 + ? gfx->data.vnc.port - 5900 : 0); + break; + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET: + virBufferAsprintf(&vnc_addr, "unix:%s", glisten->socket); + break; + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE: + virBufferAddLit(&vnc_addr, "none"); + break; + case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST: + default: + virBufferAddLit(&vnc_addr, "localhost:0"); + break; + } + + virCommandAddArg(cmd, "--vnc-addr"); + virCommandAddArgBuffer(cmd, &vnc_addr); + } + + if (gfx->data.vnc.websocket > 0) { + g_autofree char *ws = g_strdup_printf("%d", gfx->data.vnc.websocket); + virCommandAddArgPair(cmd, "--websocket", ws); + } + + if (gfx->data.vnc.sharePolicy != VIR_DOMAIN_GRAPHICS_VNC_SHARE_DEFAULT) { + virCommandAddArgPair(cmd, "--share", + virDomainGraphicsVNCSharePolicyTypeToString( + gfx->data.vnc.sharePolicy)); + } + + if (gfx->data.vnc.keymap) + virCommandAddArgPair(cmd, "--keyboard-layout", gfx->data.vnc.keymap); + + if (gfx->data.vnc.auth.passwd || cfg->vncPassword) + virCommandAddArg(cmd, "--password"); + + if (cfg->vncTLS && cfg->vncTLSx509certdir) + virCommandAddArgPair(cmd, "--tls-creds", cfg->vncTLSx509certdir); + + if (cfg->vncSASL) { + virCommandAddArg(cmd, "--sasl"); + + if (cfg->vncSASLdir) + virCommandAddEnvPair(cmd, "SASL_CONF_PATH", cfg->vncSASLdir); + } + + vnc->name_watch = g_bus_watch_name_on_connection(priv->dbusConnection, + ORG_QEMU_VNC, + G_BUS_NAME_WATCHER_FLAGS_NONE, + name_appeared_cb, + name_vanished_cb, + vnc, + NULL); + + if (qemuExtDeviceLogCommand(driver, vm, cmd, "qemu-vnc") < 0) + goto error; + + if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0) + goto error; + + if (virPidFileReadPath(pidfile, &pid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to read qemu-vnc pidfile '%1$s'"), + pidfile); + goto error; + } + + if (virProcessKill(pid, 0) != 0) { + g_autofree char *msg = NULL; + + if (domainLogContextReadFiltered(logContext, &msg, 1024) < 0) + VIR_WARN("Unable to read from qemu-vnc log"); + + virReportError(VIR_ERR_OPERATION_FAILED, + _("qemu-vnc died and reported:\n%1$s"), + NULLSTR(msg)); + goto error; + } + + vnc->pid = pid; + + return 0; + + error: + g_clear_handle_id(&vnc->name_watch, g_bus_unwatch_name); + qemuVncStop(vm, gfx); + return -1; +} + + +int +qemuVncSetPassword(virDomainObj *vm, + const char *password) +{ + qemuDomainObjPrivate *priv = vm->privateData; + g_autoptr(GVariant) args = NULL; + + args = g_variant_new("(s)", password); + + return virGDBusCallMethod(priv->dbusConnection, + NULL, + G_VARIANT_TYPE("()"), + NULL, + ORG_QEMU_VNC, + ORG_QEMU_VNC_PATH, + ORG_QEMU_VNC_IFACE, + "SetPassword", + args); +} + + +int +qemuVncReloadCertificates(virDomainObj *vm) +{ + qemuDomainObjPrivate *priv = vm->privateData; + + return virGDBusCallMethod(priv->dbusConnection, + NULL, + G_VARIANT_TYPE("()"), + NULL, + ORG_QEMU_VNC, + ORG_QEMU_VNC_PATH, + ORG_QEMU_VNC_IFACE, + "ReloadCertificates", + NULL); +} + + +int +qemuVncAddClient(virDomainObj *vm, + int fd, + bool skipauth) +{ + qemuDomainObjPrivate *priv = vm->privateData; + g_autoptr(GUnixFDList) fdlist = NULL; + g_autoptr(GVariant) args = NULL; + gint fd_idx; + + fdlist = g_unix_fd_list_new(); + fd_idx = g_unix_fd_list_append(fdlist, fd, NULL); + if (fd_idx < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to append FD to list")); + return -1; + } + + args = g_variant_new("(hb)", fd_idx, skipauth); + + return virGDBusCallMethodWithFD(priv->dbusConnection, + NULL, + G_VARIANT_TYPE("()"), + NULL, + NULL, + ORG_QEMU_VNC, + ORG_QEMU_VNC_PATH, + ORG_QEMU_VNC_IFACE, + "AddClient", + args, + fdlist); +} + + +/** + * qemuVncAvailable: + * @helper: name (or path to) 'qemu-vnc' binary + * + * Returns whether 'qemu-vnc' is available. + * + * Important: + * This function is called from 'virQEMUDriverGetDomainCapabilities'. It must + * not report any errors and must not add any additional checks. + * + * This function is mocked from 'tests/testutilsqemu.c' + */ +bool +qemuVncAvailable(const char *helper) +{ + g_autofree char *helperPath = NULL; + + return !!(helperPath = virFindFileInPath(helper)); +} diff --git a/src/qemu/qemu_vnc.h b/src/qemu/qemu_vnc.h new file mode 100644 index 0000000000..6a0d2124c5 --- /dev/null +++ b/src/qemu/qemu_vnc.h @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#pragma once + +#include "qemu_conf.h" + +typedef struct _qemuVnc qemuVnc; +struct _qemuVnc { + pid_t pid; + guint name_watch; + bool name_appeared; + guint leaving_id; +}; + +bool qemuVncAvailable(const char *helper); + +qemuVnc *qemuVncNew(void); + +void qemuVncFree(qemuVnc *vnc); + +int qemuVncStart(virDomainObj *vm, + virDomainGraphicsDef *gfx); + +void qemuVncStop(virDomainObj *vm, + virDomainGraphicsDef *gfx); + +int qemuVncSetupCgroup(qemuVnc *vnc, + virCgroup *cgroup); + +int qemuVncSetPassword(virDomainObj *vm, + const char *password); + +int qemuVncReloadCertificates(virDomainObj *vm); + +int qemuVncAddClient(virDomainObj *vm, + int fd, + bool skipauth); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuVnc, qemuVncFree); -- 2.53.0
From: Marc-André Lureau <marcandre.lureau@redhat.com> When both a D-Bus display and a VNC graphics device are configured and the qemu-vnc binary is available, use the standalone VNC server instead of QEMU's built-in VNC. During domain preparation, detect whether the standalone VNC path applies and allocate the qemuVnc context. Skip the built-in -vnc command line argument when standalone VNC is active. Start and stop the qemu-vnc process through the external device hooks. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 2 ++ src/qemu/qemu_extdevice.c | 13 +++++++++++-- src/qemu/qemu_process.c | 40 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 5b7423e354..a35205bd25 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8806,6 +8806,8 @@ qemuBuildGraphicsCommandLine(virQEMUDriverConfig *cfg, break; case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + if (QEMU_DOMAIN_GRAPHICS_PRIVATE(graphics)->vnc) + break; if (qemuBuildGraphicsVNCCommandLine(cfg, def, cmd, graphics) < 0) return -1; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 91d57ee60b..dc6282d811 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1040,6 +1040,7 @@ qemuDomainGraphicsPrivateDispose(void *obj) g_free(priv->tlsAlias); g_clear_pointer(&priv->secinfo, qemuDomainSecretInfoFree); g_clear_pointer(&priv->rdp, qemuRdpFree); + g_clear_pointer(&priv->vnc, qemuVncFree); } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index b321a64e96..24e62dd2e7 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -36,6 +36,7 @@ #include "qemu_migration_params.h" #include "qemu_nbdkit.h" #include "qemu_rdp.h" +#include "qemu_vnc.h" #include "qemu_slirp.h" #include "qemu_fd.h" #include "virchrdev.h" @@ -417,6 +418,7 @@ struct _qemuDomainGraphicsPrivate { char *tlsAlias; qemuDomainSecretInfo *secinfo; qemuRdp *rdp; + qemuVnc *vnc; }; diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c index 6e16c6be29..93a070f892 100644 --- a/src/qemu/qemu_extdevice.c +++ b/src/qemu/qemu_extdevice.c @@ -247,8 +247,14 @@ qemuExtDevicesStart(virQEMUDriver *driver, return -1; continue; } + case VIR_DOMAIN_GRAPHICS_TYPE_VNC: { + if (QEMU_DOMAIN_GRAPHICS_PRIVATE(graphics)->vnc) { + if (qemuVncStart(vm, graphics) < 0) + return -1; + } + continue; + } case VIR_DOMAIN_GRAPHICS_TYPE_SDL: - case VIR_DOMAIN_GRAPHICS_TYPE_VNC: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: @@ -327,9 +333,12 @@ qemuExtDevicesStop(virQEMUDriver *driver, qemuRdpStop(vm, graphics); continue; } + case VIR_DOMAIN_GRAPHICS_TYPE_VNC: { + qemuVncStop(vm, graphics); + continue; + } case VIR_DOMAIN_GRAPHICS_TYPE_DBUS: case VIR_DOMAIN_GRAPHICS_TYPE_SDL: - case VIR_DOMAIN_GRAPHICS_TYPE_VNC: case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS: diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 7ebc038e54..40db4fabbd 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5589,6 +5589,41 @@ qemuProcessGraphicsSetupRenderNode(virDomainGraphicsDef *graphics, } +static bool +qemuHasNonP2PDbusGraphics(virDomainDef *def) +{ + size_t i; + + for (i = 0; i < def->ngraphics; i++) { + virDomainGraphicsDef *g = def->graphics[i]; + + if (g->type == VIR_DOMAIN_GRAPHICS_TYPE_DBUS && !g->data.dbus.p2p) + return true; + } + + return false; +} + + +static int +qemuPrepareGraphicsVnc(virQEMUDriver *driver, + virDomainDef *def, + virDomainGraphicsDef *gfx) +{ + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + + if (!qemuHasNonP2PDbusGraphics(def)) + return 0; + + if (!qemuVncAvailable(cfg->qemuVncName)) + return 0; + + QEMU_DOMAIN_GRAPHICS_PRIVATE(gfx)->vnc = qemuVncNew(); + + return 0; +} + + static int qemuProcessSetupGraphics(virQEMUDriver *driver, virDomainObj *vm, @@ -5610,6 +5645,10 @@ qemuProcessSetupGraphics(virQEMUDriver *driver, if (qemuProcessGraphicsSetupDBus(driver, graphics, vm) < 0) return -1; + + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && + qemuPrepareGraphicsVnc(driver, vm->def, graphics) < 0) + return -1; } if (allocate) { @@ -6174,7 +6213,6 @@ qemuProcessPrepareGraphics(virDomainObj *vm) if (gfx->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP && qemuPrepareGraphicsRdp(priv->driver, gfx) < 0) return -1; - } return 0; -- 2.53.0
From: Marc-André Lureau <marcandre.lureau@redhat.com> Route the OpenGraphics, OpenGraphicsFD, and GraphicsReload driver APIs through the standalone qemu-vnc D-Bus interface when active. Client connections are passed via D-Bus fd-passing (AddClient), certificate reloading uses the ReloadCertificates method, and password changes use SetPassword. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- src/qemu/qemu_driver.c | 56 +++++++++++++++++++++++++++++++++++------ src/qemu/qemu_hotplug.c | 12 +++++++++ 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 83d0bab126..d79d68001f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -41,6 +41,7 @@ #include "qemu_hotplug.h" #include "qemu_monitor.h" #include "qemu_passt.h" +#include "qemu_vnc.h" #include "qemu_process.h" #include "qemu_migration.h" #include "qemu_migration_params.h" @@ -14946,6 +14947,11 @@ qemuDomainOpenGraphics(virDomainPtr dom, } switch (vm->def->graphics[idx]->type) { case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + if (QEMU_DOMAIN_GRAPHICS_PRIVATE(vm->def->graphics[idx])->vnc) { + ret = qemuVncAddClient(vm, fd, + (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH) != 0); + goto endjob; + } protocol = "vnc"; break; case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: @@ -14985,6 +14991,25 @@ qemuDomainOpenGraphics(virDomainPtr dom, return ret; } + +static int +qemuSocketPair(int pair[2], + virSecurityManager *mgr, + virDomainDef *vm) +{ + if (qemuSecuritySetSocketLabel(mgr, vm) < 0) + return -1; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) + return -1; + + if (qemuSecurityClearSocketLabel(mgr, vm) < 0) + return -1; + + return 0; +} + + static int qemuDomainOpenGraphicsFD(virDomainPtr dom, unsigned int idx, @@ -15017,6 +15042,18 @@ qemuDomainOpenGraphicsFD(virDomainPtr dom, } switch (vm->def->graphics[idx]->type) { case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + if (QEMU_DOMAIN_GRAPHICS_PRIVATE(vm->def->graphics[idx])->vnc) { + if (qemuSocketPair(pair, driver->securityManager, vm->def) < 0) + goto cleanup; + + if (qemuVncAddClient(vm, pair[1], + (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH) != 0) < 0) + goto cleanup; + + ret = pair[0]; + pair[0] = -1; + goto cleanup; + } protocol = "vnc"; break; case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: @@ -15040,13 +15077,7 @@ qemuDomainOpenGraphicsFD(virDomainPtr dom, goto cleanup; } - if (qemuSecuritySetSocketLabel(driver->securityManager, vm->def) < 0) - goto cleanup; - - if (socketpair(PF_UNIX, SOCK_STREAM, 0, pair) < 0) - goto cleanup; - - if (qemuSecurityClearSocketLabel(driver->securityManager, vm->def) < 0) + if (qemuSocketPair(pair, driver->securityManager, vm->def) < 0) goto cleanup; if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) @@ -20445,6 +20476,7 @@ qemuDomainGraphicsReload(virDomainPtr domain, int ret = -1; virDomainObj *vm = NULL; qemuDomainObjPrivate *priv; + size_t j; virCheckFlagsGoto(0, cleanup); @@ -20486,6 +20518,16 @@ qemuDomainGraphicsReload(virDomainPtr domain, priv = vm->privateData; + for (j = 0; j < vm->def->ngraphics; j++) { + virDomainGraphicsDef *gfx = vm->def->graphics[j]; + + if (gfx->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && + QEMU_DOMAIN_GRAPHICS_PRIVATE(gfx)->vnc) { + ret = qemuVncReloadCertificates(vm); + goto endjob; + } + } + qemuDomainObjEnterMonitor(vm); ret = qemuMonitorDisplayReload(priv->mon, "vnc", true); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index b7a282b96e..404cec4a94 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -4543,6 +4543,18 @@ qemuDomainChangeGraphicsPasswords(virDomainObj *vm, return qemuRdpSetCredentials(vm, username, password, ""); } + if (type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { + size_t i; + + for (i = 0; i < vm->def->ngraphics; i++) { + virDomainGraphicsDef *gfx = vm->def->graphics[i]; + + if (gfx->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && + QEMU_DOMAIN_GRAPHICS_PRIVATE(gfx)->vnc) + return qemuVncSetPassword(vm, password); + } + } + if (auth->connected) connected = virDomainGraphicsAuthConnectedTypeToString(auth->connected); -- 2.53.0
From: Marc-André Lureau <marcandre.lureau@redhat.com> Add xml2argv tests verifying the standalone VNC feature: - graphics-vnc-standalone: when both <graphics type='dbus'/> and <graphics type='vnc'/> are present, the -vnc QEMU argument is omitted since qemu-vnc handles VNC externally via D-Bus. - graphics-vnc-standalone-socket: same behavior with a Unix socket listen address. - graphics-vnc-standalone-p2p: when dbus is p2p mode, standalone VNC is NOT triggered and the built-in -vnc argument is preserved. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> --- ...hics-vnc-standalone-p2p.x86_64-latest.args | 34 ++++++++++++++++ ...phics-vnc-standalone-p2p.x86_64-latest.xml | 40 +++++++++++++++++++ .../graphics-vnc-standalone-p2p.xml | 39 ++++++++++++++++++ ...s-vnc-standalone-socket.x86_64-latest.args | 33 +++++++++++++++ ...cs-vnc-standalone-socket.x86_64-latest.xml | 40 +++++++++++++++++++ .../graphics-vnc-standalone-socket.xml | 40 +++++++++++++++++++ ...graphics-vnc-standalone.x86_64-latest.args | 33 +++++++++++++++ .../graphics-vnc-standalone.x86_64-latest.xml | 40 +++++++++++++++++++ .../graphics-vnc-standalone.xml | 40 +++++++++++++++++++ tests/qemuxmlconftest.c | 4 ++ tests/testutilsqemu.c | 9 +++++ 11 files changed, 352 insertions(+) create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone-socket.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/graphics-vnc-standalone.xml diff --git a/tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.args b/tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.args new file mode 100644 index 0000000000..081219b757 --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.args @@ -0,0 +1,34 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \ +-accel tcg \ +-cpu qemu64 \ +-m size=219136k \ +-object '{"qom-type":"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 \ +-boot strict=on \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-display dbus,p2p=on \ +-vnc 127.0.0.1:3,audiodev=audio1 \ +-device '{"driver":"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/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.xml b/tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.xml new file mode 100644 index 0000000000..d07187e525 --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.x86_64-latest.xml @@ -0,0 +1,40 @@ +<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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus' p2p='yes'/> + <graphics type='vnc' port='5903' autoport='no' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <audio id='1' type='none'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.xml b/tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.xml new file mode 100644 index 0000000000..956dc8a185 --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone-p2p.xml @@ -0,0 +1,39 @@ +<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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus' p2p='yes'/> + <graphics type='vnc' port='5903' autoport='no' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.args b/tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.args new file mode 100644 index 0000000000..eb1f27e6cd --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.args @@ -0,0 +1,33 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \ +-accel tcg \ +-cpu qemu64 \ +-m size=219136k \ +-object '{"qom-type":"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 \ +-boot strict=on \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \ +-audiodev '{"id":"audio1","driver":"dbus"}' \ +-display dbus,addr=unix:path=/var/run/libvirt/qemu/dbus/-1-QEMUGuest1-dbus.sock \ +-device '{"driver":"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/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.xml b/tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.xml new file mode 100644 index 0000000000..0e0a177a28 --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone-socket.x86_64-latest.xml @@ -0,0 +1,40 @@ +<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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus'/> + <graphics type='vnc' socket='/tmp/vnc.sock'> + <listen type='socket' socket='/tmp/vnc.sock'/> + </graphics> + <audio id='1' type='dbus'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxmlconfdata/graphics-vnc-standalone-socket.xml b/tests/qemuxmlconfdata/graphics-vnc-standalone-socket.xml new file mode 100644 index 0000000000..21694125b0 --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone-socket.xml @@ -0,0 +1,40 @@ +<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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus'/> + <graphics type='vnc'> + <listen type='socket' socket='/tmp/vnc.sock'/> + </graphics> + <audio id='1' type='dbus'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.args b/tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.args new file mode 100644 index 0000000000..eb1f27e6cd --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.args @@ -0,0 +1,33 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \ +-accel tcg \ +-cpu qemu64 \ +-m size=219136k \ +-object '{"qom-type":"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 \ +-boot strict=on \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \ +-audiodev '{"id":"audio1","driver":"dbus"}' \ +-display dbus,addr=unix:path=/var/run/libvirt/qemu/dbus/-1-QEMUGuest1-dbus.sock \ +-device '{"driver":"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/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.xml b/tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.xml new file mode 100644 index 0000000000..030de05a11 --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone.x86_64-latest.xml @@ -0,0 +1,40 @@ +<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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus'/> + <graphics type='vnc' port='5903' autoport='no' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <audio id='1' type='dbus'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxmlconfdata/graphics-vnc-standalone.xml b/tests/qemuxmlconfdata/graphics-vnc-standalone.xml new file mode 100644 index 0000000000..030de05a11 --- /dev/null +++ b/tests/qemuxmlconfdata/graphics-vnc-standalone.xml @@ -0,0 +1,40 @@ +<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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='dbus'/> + <graphics type='vnc' port='5903' autoport='no' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <audio id='1' type='dbus'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c index 4c9b55693a..9b14debbd8 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -1692,6 +1692,10 @@ mymain(void) DO_TEST_CAPS_LATEST("graphics-rdp"); + DO_TEST_CAPS_LATEST("graphics-vnc-standalone"); + DO_TEST_CAPS_LATEST("graphics-vnc-standalone-socket"); + DO_TEST_CAPS_LATEST("graphics-vnc-standalone-p2p"); + DO_TEST_CAPS_LATEST("input-usbmouse"); DO_TEST_CAPS_LATEST("input-usbtablet"); diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index e9bdbdbbe7..1f746743bb 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -59,6 +59,13 @@ bool qemuRdpAvailable(const char *helper G_GNUC_UNUSED) } +/* Enough to tell capabilities code that qemu-vnc is usable */ +bool qemuVncAvailable(const char *helper G_GNUC_UNUSED) +{ + return true; +} + + bool virTPMSwtpmSetupCapsGet(virTPMSwtpmSetupFeature cap) { @@ -343,6 +350,8 @@ int qemuTestDriverInit(virQEMUDriver *driver) cfg->dbusStateDir = g_strdup("/var/run/libvirt/qemu/dbus"); VIR_FREE(cfg->rdpStateDir); cfg->rdpStateDir = g_strdup("/var/run/libvirt/qemu/rdp"); + VIR_FREE(cfg->vncStateDir); + cfg->vncStateDir = g_strdup("/var/run/libvirt/qemu/vnc"); if (!g_mkdtemp(statedir)) { fprintf(stderr, "Cannot create fake stateDir"); -- 2.53.0
participants (1)
-
marcandre.lureau@redhat.com