From 30c43afd73e8c2931dc210562066ba37a8b9fe26 Mon Sep 17 00:00:00 2001
From: Michal Privoznik
Date: Thu, 26 May 2011 16:15:54 +0200
Subject: [PATCH] graphics: add support for action_if_connected in qemu
This option accepts 3 values:
-keep, to keep current client connected (Spice+VNC)
-disconnect, to disconnect client (Spice)
-fail, to fail setting password if there is a client connected (Spice)
---
docs/formatdomain.html.in | 23 +++++++---
docs/schemas/domain.rng | 16 +++++++
src/conf/domain_conf.c | 44 +++++++++++++++++--
src/conf/domain_conf.h | 11 +++++
src/libvirt_private.syms | 2 +
src/qemu/qemu_hotplug.c | 15 +++++--
.../qemuxml2argv-graphics-spice-timeout.xml | 2 +-
7 files changed, 99 insertions(+), 14 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 10d87a9bb6..fa4e0c23b7 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1896,11 +1896,14 @@ qemu-kvm -net nic,model=? /dev/null
specifies the keymap to use. It is possible to set a limit
on the validity of the password be giving an
timestamp passwdValidTo='2010-04-09T15:51:00'
- assumed to be in UTC. NB, this may not be supported by all
- hypervisors.
Rather than using listen/port,
- QEMU supports a socket attribute for
- listening on a unix domain socket
- path.Since 0.8.8
+ assumed to be in UTC. The connected attribute
+ allows control of connected client during password changes.
+ VNC accepts keep value only.
+ since 0.9.3
+ NB, this may not be supported by all hypervisors.
+ Rather than using listen/port, QEMU supports a
+ socket attribute for listening on a unix
+ domain socket path.Since 0.8.8
"spice"
@@ -1918,8 +1921,14 @@ qemu-kvm -net nic,model=? /dev/null
attribute specifies the keymap to use. It is possible to
set a limit on the validity of the password be giving an
timestamp passwdValidTo='2010-04-09T15:51:00'
- assumed to be in UTC. NB, this may not be supported by
- all hypervisors."spice" since 0.8.6.
+ assumed to be in UTC. The connected attribute
+ allows control of connected client during password changes.
+ SPICE accepts keep to keep client connected,
+ disconnect to disconnect client and
+ fail to fail changing password.
+ Since 0.9.3
+ NB, this may not be supported by all hypervisors.
+ "spice" since 0.8.6.
When SPICE has both a normal and TLS secured TCP port
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 3c8414eef0..c01801e4cd 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -1294,6 +1294,13 @@
+
+
+
+ keep
+
+
+
@@ -1337,6 +1344,15 @@
+
+
+
+ fail
+ disconnect
+ keep
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 2275d3ae5b..a680b114e8 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -317,6 +317,13 @@ VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
"desktop",
"spice")
+VIR_ENUM_IMPL(virDomainGraphicsAuthConnected,
+ VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_LAST,
+ "default",
+ "fail",
+ "disconnect",
+ "keep")
+
VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelName,
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST,
"main",
@@ -3945,9 +3952,12 @@ error:
static int
-virDomainGraphicsAuthDefParseXML(xmlNodePtr node, virDomainGraphicsAuthDefPtr def)
+virDomainGraphicsAuthDefParseXML(xmlNodePtr node,
+ virDomainGraphicsAuthDefPtr def,
+ int type)
{
char *validTo = NULL;
+ char *connected = virXMLPropString(node, "connected");
def->passwd = virXMLPropString(node, "passwd");
@@ -3988,6 +3998,28 @@ virDomainGraphicsAuthDefParseXML(xmlNodePtr node, virDomainGraphicsAuthDefPtr de
def->expires = 1;
}
+ if (connected) {
+ int action = virDomainGraphicsAuthConnectedTypeFromString(connected);
+ if (action <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown connected value %s"),
+ connected);
+ VIR_FREE(connected);
+ return -1;
+ }
+ VIR_FREE(connected);
+
+ /* VNC supports connected='keep' only */
+ if (type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
+ action != VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("VNC supports connected='keep' only"));
+ return -1;
+ }
+
+ def->connected = action;
+ }
+
return 0;
}
@@ -4058,7 +4090,8 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, unsigned int flags)
!def->data.vnc.listenAddr[0])
VIR_FREE(def->data.vnc.listenAddr);
- if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0)
+ if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth,
+ def->type) < 0)
goto error;
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
char *fullscreen = virXMLPropString(node, "fullscreen");
@@ -4194,7 +4227,8 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, unsigned int flags)
!def->data.spice.listenAddr[0])
VIR_FREE(def->data.spice.listenAddr);
- if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth) < 0)
+ if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth,
+ def->type) < 0)
goto error;
cur = node->children;
@@ -9280,6 +9314,10 @@ virDomainGraphicsAuthDefFormatAttr(virBufferPtr buf,
strftime(strbuf, sizeof(strbuf), "%Y-%m-%dT%H:%M:%S", tm);
virBufferAsprintf(buf, " passwdValidTo='%s'", strbuf);
}
+
+ if (def->connected)
+ virBufferEscapeString(buf, " connected='%s'",
+ virDomainGraphicsAuthConnectedTypeToString(def->connected));
}
static int
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ddfe18e3d9..15adc70b88 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -639,12 +639,22 @@ enum virDomainGraphicsType {
VIR_DOMAIN_GRAPHICS_TYPE_LAST,
};
+enum virDomainGraphicsAuthConnectedType {
+ VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DEFAULT = 0,
+ VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_FAIL,
+ VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DISCONNECT,
+ VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP,
+
+ VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_LAST
+};
+
typedef struct _virDomainGraphicsAuthDef virDomainGraphicsAuthDef;
typedef virDomainGraphicsAuthDef *virDomainGraphicsAuthDefPtr;
struct _virDomainGraphicsAuthDef {
char *passwd;
unsigned int expires: 1; /* Whether there is an expiry time set */
time_t validTo; /* seconds since epoch */
+ int connected; /* action if connected */
};
enum virDomainGraphicsSpiceChannelName {
@@ -1582,6 +1592,7 @@ VIR_ENUM_DECL(virDomainHostdevSubsys)
VIR_ENUM_DECL(virDomainInput)
VIR_ENUM_DECL(virDomainInputBus)
VIR_ENUM_DECL(virDomainGraphics)
+VIR_ENUM_DECL(virDomainGraphicsAuthConnected)
VIR_ENUM_DECL(virDomainGraphicsSpiceChannelName)
VIR_ENUM_DECL(virDomainGraphicsSpiceChannelMode)
VIR_ENUM_DECL(virDomainGraphicsSpiceImageCompression)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 28a34045f7..1112398642 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -270,6 +270,8 @@ virDomainFindByID;
virDomainFindByName;
virDomainFindByUUID;
virDomainGetRootFilesystem;
+virDomainGraphicsAuthConnectedTypeFromString;
+virDomainGraphicsAuthConnectedTypeToString;
virDomainGraphicsDefFree;
virDomainGraphicsSpiceChannelModeTypeFromString;
virDomainGraphicsSpiceChannelModeTypeToString;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index a7f11ab436..58689f688a 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1065,10 +1065,12 @@ qemuDomainChangeGraphics(struct qemud_driver *driver,
return -1;
}
- /* If a password lifetime was, or is set, then we must always run,
- * even if new password matches old password */
+ /* If a password lifetime was, or is set, or action if connected has
+ * changed, then we must always run, even if new password matches
+ * old password */
if (olddev->data.vnc.auth.expires ||
dev->data.vnc.auth.expires ||
+ olddev->data.vnc.auth.connected != dev->data.vnc.auth.connected ||
STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd,
dev->data.vnc.auth.passwd)) {
VIR_DEBUG("Updating password on VNC server %p %p",
@@ -1084,6 +1086,7 @@ qemuDomainChangeGraphics(struct qemud_driver *driver,
dev->data.vnc.auth.passwd = NULL;
olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo;
olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires;
+ olddev->data.vnc.auth.connected = dev->data.vnc.auth.connected;
} else {
ret = 0;
}
@@ -1116,6 +1119,7 @@ qemuDomainChangeGraphics(struct qemud_driver *driver,
* even if new password matches old password */
if (olddev->data.spice.auth.expires ||
dev->data.spice.auth.expires ||
+ olddev->data.spice.auth.connected != dev->data.spice.auth.connected ||
STRNEQ_NULLABLE(olddev->data.spice.auth.passwd,
dev->data.spice.auth.passwd)) {
VIR_DEBUG("Updating password on SPICE server %p %p",
@@ -1131,6 +1135,7 @@ qemuDomainChangeGraphics(struct qemud_driver *driver,
dev->data.spice.auth.passwd = NULL;
olddev->data.spice.auth.validTo = dev->data.spice.auth.validTo;
olddev->data.spice.auth.expires = dev->data.spice.auth.expires;
+ olddev->data.spice.auth.connected = dev->data.spice.auth.connected;
} else {
VIR_DEBUG("Not updating since password didn't change");
ret = 0;
@@ -1874,16 +1879,20 @@ qemuDomainChangeGraphicsPasswords(struct qemud_driver *driver,
qemuDomainObjPrivatePtr priv = vm->privateData;
time_t now = time(NULL);
char expire_time [64];
+ const char *connected = NULL;
int ret;
if (!auth->passwd && !driver->vncPassword)
return 0;
+ if (auth->connected)
+ connected = virDomainGraphicsAuthConnectedTypeToString(auth->connected);
+
qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorSetPassword(priv->mon,
type,
auth->passwd ? auth->passwd : defaultPasswd,
- NULL);
+ connected);
if (ret == -2) {
if (type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml
index 4c0c57edf2..6389de54ad 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml
@@ -71,7 +71,7 @@
-
+