This patch adds the host UUID (to the capabilities of libvirt). The user
may provide it in libvirtd.conf overriding whatever sysfs may
return. If none or no valid UUID is provided in libvirtd.conf, reading the
UUID from sysfs is attempted. If that function doesn't provide a valid
(not all digits may be equal), generate a temporary one.
virSetHostUUIDStr() should be called first with the UUID read from
libvirtd.conf, but may only be called once. Subsequently the function
virGetHostUUID() can be called to get the UUID of the host.
changes from V2 to V3:
- addressing more comments from D. Berrange:
- removing virGetHostUUIDStr() function
- adding uuid to all test cases' data files
- failing libvirt if host_uuid is malformatted or considered invalid
- extended virCapsHost with host_uuid field
- initializing virCapsHost's host_uuid field in qemu_driver's init function
Changes from V1 to V2:
- addressing comments from Daniel Berrange:
- rewrite/ code to get the UUID from 2 possible sysfs files
- got rid of dmidecide dependency
- call the newly added virGetHostUUID() function in udevGetDMIData() to get
the UUID of the host ( even if it's just a temporary UUID )
Besides that, this patch
- adds uuid to the capabilties XML schema
- displays the UUID in in 'virsh capabilities'
- adds 3 public functions to uuid.h for setting and getting the UUID of
the host
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
daemon/libvirtd.c | 9 ++
daemon/libvirtd.conf | 10 ++
docs/schemas/capability.rng | 14 +++
src/conf/capabilities.c | 5 +
src/conf/capabilities.h | 1
src/libvirt_private.syms | 2
src/node_device/node_device_udev.c | 6 -
src/qemu/qemu_driver.c | 6 +
src/util/uuid.c | 116 +++++++++++++++++++++++++++
src/util/uuid.h | 3
tests/capabilityschemadata/caps-qemu-kvm.xml | 1
tests/capabilityschemadata/caps-test.xml | 1
tests/confdata/libvirtd.conf | 9 ++
tests/confdata/libvirtd.out | 7 +
tests/xencapsdata/xen-i686-pae-hvm.xml | 1
tests/xencapsdata/xen-i686-pae.xml | 1
tests/xencapsdata/xen-i686.xml | 1
tests/xencapsdata/xen-ia64-be-hvm.xml | 1
tests/xencapsdata/xen-ia64-be.xml | 1
tests/xencapsdata/xen-ia64-hvm.xml | 1
tests/xencapsdata/xen-ia64.xml | 1
tests/xencapsdata/xen-ppc64.xml | 1
tests/xencapsdata/xen-x86_64-hvm.xml | 1
tests/xencapsdata/xen-x86_64.xml | 1
24 files changed, 195 insertions(+), 5 deletions(-)
Index: libvirt-acl/daemon/libvirtd.c
===================================================================
--- libvirt-acl.orig/daemon/libvirtd.c
+++ libvirt-acl/daemon/libvirtd.c
@@ -57,6 +57,7 @@
#include "dispatch.h"
#include "util.h"
+#include "uuid.h"
#include "remote_driver.h"
#include "conf.h"
#include "event.h"
@@ -2718,6 +2719,7 @@ remoteReadConfigFile (struct qemud_serve
char *unix_sock_rw_perms = NULL;
char *unix_sock_group = NULL;
char *buf = NULL;
+ char *host_uuid = NULL;
#if HAVE_POLKIT
/* Change the default back to no auth for non-root */
@@ -2840,11 +2842,18 @@ remoteReadConfigFile (struct qemud_serve
GET_CONF_INT (conf, filename, max_requests);
GET_CONF_INT (conf, filename, max_client_requests);
+ GET_CONF_STR (conf, filename, host_uuid);
+ if (virSetHostUUIDStr(host_uuid))
+ goto free_and_fail;
+
+ VIR_FREE(host_uuid);
+
virConfFree (conf);
return 0;
free_and_fail:
virConfFree (conf);
+ VIR_FREE(host_uuid);
VIR_FREE(mdns_name);
VIR_FREE(unix_sock_ro_perms);
VIR_FREE(unix_sock_rw_perms);
Index: libvirt-acl/src/util/uuid.h
===================================================================
--- libvirt-acl.orig/src/util/uuid.h
+++ libvirt-acl/src/util/uuid.h
@@ -22,6 +22,9 @@
#ifndef __VIR_UUID_H__
# define __VIR_UUID_H__
+int virSetHostUUIDStr(const char *host_uuid);
+int virGetHostUUID(unsigned char *host_uuid);
+
int virUUIDGenerate(unsigned char *uuid);
int virUUIDParse(const char *uuidstr,
Index: libvirt-acl/src/util/uuid.c
===================================================================
--- libvirt-acl.orig/src/util/uuid.c
+++ libvirt-acl/src/util/uuid.c
@@ -38,11 +38,14 @@
#include "util.h"
#include "virterror_internal.h"
#include "logging.h"
+#include "memory.h"
#ifndef ENODATA
# define ENODATA EIO
#endif
+static unsigned char host_uuid[VIR_UUID_BUFLEN];
+
static int
virUUIDGenerateRandomBytes(unsigned char *buf,
int buflen)
@@ -208,3 +211,116 @@ void virUUIDFormat(const unsigned char *
uuid[12], uuid[13], uuid[14], uuid[15]);
uuidstr[VIR_UUID_STRING_BUFLEN-1] = '\0';
}
+
+
+
+/**
+ * isValidHostUUID
+ *
+ * @uuid: The UUID to test
+ *
+ * Do some basic tests to check whether the given UUID is
+ * valid as a host UUID.
+ * Basic tests:
+ * - Not all of the digits may be equal
+ */
+static int
+isValidHostUUID(unsigned char *uuid)
+{
+ unsigned int i, ctr = 1;
+ unsigned char c;
+
+ if (!uuid)
+ return 0;
+
+ c = uuid[0];
+
+ for (i = 1; i < VIR_UUID_BUFLEN; i++)
+ if (uuid[i] == c)
+ ctr++;
+
+ return (ctr != VIR_UUID_BUFLEN);
+}
+
+static int
+getDMISystemUUID(char *uuid, int len)
+{
+ unsigned int i = 0;
+ const char *paths[] = {
+ "/sys/devices/virtual/dmi/id/product_uuid",
+ "/sys/class/dmi/id/product_uuid",
+ NULL
+ };
+
+ while (paths[i]) {
+ int fd = open(paths[i], O_RDONLY);
+ if (fd > 0) {
+ if (saferead(fd, uuid, len) == len) {
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ }
+ i++;
+ }
+
+ return -1;
+}
+
+
+/**
+ * setHostUUID
+ *
+ * @host_uuid: UUID that the host is supposed to have
+ *
+ * Set the UUID of the host if it hasn't been set, yet
+ * Returns 0 in case of success, an error code in case of error.
+ */
+int
+virSetHostUUIDStr(const char *uuid)
+{
+ int rc;
+ char dmiuuid[VIR_UUID_STRING_BUFLEN];
+
+ if (isValidHostUUID(host_uuid))
+ return EEXIST;
+
+ if (!uuid) {
+ if (!getDMISystemUUID(dmiuuid, sizeof(dmiuuid))) {
+ if (!virUUIDParse(dmiuuid, host_uuid))
+ return 0;
+ }
+ } else {
+ rc = virUUIDParse(uuid, host_uuid);
+ if (rc)
+ return rc;
+ if (!isValidHostUUID(host_uuid))
+ return EINVAL;
+ }
+
+ if (!isValidHostUUID(host_uuid))
+ return virUUIDGenerate(host_uuid);
+
+ return 0;
+}
+
+/**
+ * getHostUUID:
+ *
+ * @host_uuid: memory to store the host_uuid into
+ *
+ * Get the UUID of the host. Returns 0 in case of success,
+ * an error code otherwise.
+ * Returns 0 in case of success, an error code in case of error.
+ */
+int virGetHostUUID(unsigned char *uuid)
+{
+ int ret = 0;
+
+ if (!isValidHostUUID(host_uuid))
+ ret = virSetHostUUIDStr(NULL);
+
+ memcpy(uuid, host_uuid, sizeof(host_uuid));
+
+ return ret;
+}
Index: libvirt-acl/src/conf/capabilities.c
===================================================================
--- libvirt-acl.orig/src/conf/capabilities.c
+++ libvirt-acl/src/conf/capabilities.c
@@ -27,6 +27,7 @@
#include "buf.h"
#include "memory.h"
#include "util.h"
+#include "uuid.h"
#include "cpu_conf.h"
/**
@@ -662,9 +663,13 @@ virCapabilitiesFormatXML(virCapsPtr caps
{
virBuffer xml = VIR_BUFFER_INITIALIZER;
int i, j, k;
+ char host_uuid[VIR_UUID_STRING_BUFLEN];
+
+ virUUIDFormat(caps->host.host_uuid, host_uuid);
virBufferAddLit(&xml, "<capabilities>\n\n");
virBufferAddLit(&xml, " <host>\n");
+ virBufferVSprintf(&xml," <uuid>%s</uuid>\n",
host_uuid);
virBufferAddLit(&xml, " <cpu>\n");
virBufferVSprintf(&xml, " <arch>%s</arch>\n",
caps->host.arch);
Index: libvirt-acl/docs/schemas/capability.rng
===================================================================
--- libvirt-acl.orig/docs/schemas/capability.rng
+++ libvirt-acl/docs/schemas/capability.rng
@@ -18,6 +18,9 @@
<define name='hostcaps'>
<element name='host'>
+ <element name='uuid'>
+ <ref name='UUID'/>
+ </element>
<element name='cpu'>
<element name='arch'>
<ref name='archnames'/>
@@ -349,4 +352,15 @@
<param name='pattern'>[a-zA-Z0-9\-_]+</param>
</data>
</define>
+
+ <define name="UUID">
+ <choice>
+ <data type="string">
+ <param name="pattern">[a-fA-F0-9]{32}</param>
+ </data>
+ <data type="string">
+ <param
name="pattern">[a-fA-F0-9]{8}\-([a-fA-F0-9]{4}\-){3}[a-fA-F0-9]{12}</param>
+ </data>
+ </choice>
+ </define>
</grammar>
Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -708,6 +708,8 @@ usbDeviceFileIterate;
virUUIDFormat;
virUUIDGenerate;
virUUIDParse;
+virSetHostUUIDStr;
+virGetHostUUID;
# virterror_internal.h
Index: libvirt-acl/daemon/libvirtd.conf
===================================================================
--- libvirt-acl.orig/daemon/libvirtd.conf
+++ libvirt-acl/daemon/libvirtd.conf
@@ -312,3 +312,13 @@
# e.g.:
# log_outputs="3:syslog:libvirtd"
# to log all warnings and errors to syslog under the libvirtd ident
+
+# UUID of the host:
+# Provide the UUID of the host here in case the command
+# 'dmidecode -s system-uuid' does not provide a valid uuid. In case
+# 'dmidecode' does not provide a valid UUID and none is provided here, a
+# temporary UUID will be generated.
+# Keep the format of the example UUID below. UUID must not have all digits
+# be the same.
+
+#host_uuid = "8510b1a1-1afa-4da6-8111-785fae202c1e"
Index: libvirt-acl/src/node_device/node_device_udev.c
===================================================================
--- libvirt-acl.orig/src/node_device/node_device_udev.c
+++ libvirt-acl/src/node_device/node_device_udev.c
@@ -1473,12 +1473,8 @@ udevGetDMIData(union _virNodeDevCapData
goto out;
}
- if (udevGetStringSysfsAttr(device,
- "product_uuid",
- &tmp) == PROPERTY_ERROR) {
+ if (virGetHostUUID(data->system.hardware.uuid))
goto out;
- }
- virUUIDParse(tmp, data->system.hardware.uuid);
if (udevGetStringSysfsAttr(device,
"bios_vendor",
Index: libvirt-acl/tests/capabilityschemadata/caps-qemu-kvm.xml
===================================================================
--- libvirt-acl.orig/tests/capabilityschemadata/caps-qemu-kvm.xml
+++ libvirt-acl/tests/capabilityschemadata/caps-qemu-kvm.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>x86_64</arch>
</cpu>
Index: libvirt-acl/tests/capabilityschemadata/caps-test.xml
===================================================================
--- libvirt-acl.orig/tests/capabilityschemadata/caps-test.xml
+++ libvirt-acl/tests/capabilityschemadata/caps-test.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>i686</arch>
<features>
Index: libvirt-acl/tests/xencapsdata/xen-i686-pae-hvm.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-i686-pae-hvm.xml
+++ libvirt-acl/tests/xencapsdata/xen-i686-pae-hvm.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>i686</arch>
<features>
Index: libvirt-acl/tests/xencapsdata/xen-i686-pae.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-i686-pae.xml
+++ libvirt-acl/tests/xencapsdata/xen-i686-pae.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>i686</arch>
<features>
Index: libvirt-acl/tests/xencapsdata/xen-i686.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-i686.xml
+++ libvirt-acl/tests/xencapsdata/xen-i686.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>i686</arch>
</cpu>
Index: libvirt-acl/tests/xencapsdata/xen-ia64-be-hvm.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-ia64-be-hvm.xml
+++ libvirt-acl/tests/xencapsdata/xen-ia64-be-hvm.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>ia64</arch>
</cpu>
Index: libvirt-acl/tests/xencapsdata/xen-ia64-be.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-ia64-be.xml
+++ libvirt-acl/tests/xencapsdata/xen-ia64-be.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>ia64</arch>
</cpu>
Index: libvirt-acl/tests/xencapsdata/xen-ia64-hvm.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-ia64-hvm.xml
+++ libvirt-acl/tests/xencapsdata/xen-ia64-hvm.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>ia64</arch>
</cpu>
Index: libvirt-acl/tests/xencapsdata/xen-ia64.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-ia64.xml
+++ libvirt-acl/tests/xencapsdata/xen-ia64.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>ia64</arch>
</cpu>
Index: libvirt-acl/tests/xencapsdata/xen-ppc64.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-ppc64.xml
+++ libvirt-acl/tests/xencapsdata/xen-ppc64.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>ppc64</arch>
</cpu>
Index: libvirt-acl/tests/xencapsdata/xen-x86_64-hvm.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-x86_64-hvm.xml
+++ libvirt-acl/tests/xencapsdata/xen-x86_64-hvm.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>x86_64</arch>
<features>
Index: libvirt-acl/tests/xencapsdata/xen-x86_64.xml
===================================================================
--- libvirt-acl.orig/tests/xencapsdata/xen-x86_64.xml
+++ libvirt-acl/tests/xencapsdata/xen-x86_64.xml
@@ -1,6 +1,7 @@
<capabilities>
<host>
+ <uuid>29b3d3aa-7ff5-3c36-ae20-ea64941ce1b2</uuid>
<cpu>
<arch>x86_64</arch>
<features>
Index: libvirt-acl/tests/confdata/libvirtd.conf
===================================================================
--- libvirt-acl.orig/tests/confdata/libvirtd.conf
+++ libvirt-acl/tests/confdata/libvirtd.conf
@@ -218,3 +218,12 @@ tls_allowed_dn_list = ["DN1", "DN2"]
#
# By default, no Username's are checked
sasl_allowed_username_list = ["joe(a)EXAMPLE.COM", "fred(a)EXAMPLE.COM"
]
+
+# UUID of the host:
+# Provide the UUID of the host here in case the command
+# 'dmidecode -s system-uuid' does not provide a valid uuid. In case
+# 'dmidecode' does not provide a valid UUID and none is provided here, a
+# temporary UUID will be generated.
+# Keep the format of the example UUID below.
+
+host_uuid = "8510b1a1-1afa-4da6-8111-785fae202c1e"
Index: libvirt-acl/tests/confdata/libvirtd.out
===================================================================
--- libvirt-acl.orig/tests/confdata/libvirtd.out
+++ libvirt-acl/tests/confdata/libvirtd.out
@@ -178,3 +178,10 @@ tls_allowed_dn_list = [ "DN1", "DN2" ]
#
# By default, no Username's are checked
sasl_allowed_username_list = [ "joe(a)EXAMPLE.COM", "fred(a)EXAMPLE.COM"
]
+# UUID of the host:
+# Provide the UUID of the host here in case the command
+# 'dmidecode -s system-uuid' does not provide a valid uuid. In case
+# 'dmidecode' does not provide a valid UUID and none is provided here, a
+# temporary UUID will be generated.
+# Keep the format of the example UUID below.
+host_uuid = "8510b1a1-1afa-4da6-8111-785fae202c1e"
Index: libvirt-acl/src/conf/capabilities.h
===================================================================
--- libvirt-acl.orig/src/conf/capabilities.h
+++ libvirt-acl/src/conf/capabilities.h
@@ -110,6 +110,7 @@ struct _virCapsHost {
virCapsHostNUMACellPtr *numaCell;
virCapsHostSecModel secModel;
virCPUDefPtr cpu;
+ unsigned char host_uuid[VIR_UUID_BUFLEN];
};
typedef struct _virCaps virCaps;
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -1334,6 +1334,11 @@ qemuCreateCapabilities(virCapsPtr oldcap
caps->privateDataXMLFormat = qemuDomainObjPrivateXMLFormat;
caps->privateDataXMLParse = qemuDomainObjPrivateXMLParse;
+ if (virGetHostUUID(caps->host.host_uuid)) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot get the host uuid"));
+ goto err_exit;
+ }
/* Security driver data */
if (driver->securityPrimaryDriver) {
@@ -1355,6 +1360,7 @@ qemuCreateCapabilities(virCapsPtr oldcap
no_memory:
virReportOOMError();
+err_exit:
virCapabilitiesFree(caps);
return NULL;
}