The virEmulatorCapabilities is going to hold emulator capabilities,
surprisingly. It's intended to be able to cover qemuCaps, lxcCaps
(once we invent them, if ever) and so on. Among with adding the code
itself, both some documentation and basic testing is introduced too.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
docs/formatemulatorcaps.html.in | 52 ++++++++
docs/schemas/Makefile.am | 1 +
docs/schemas/emulatorcapability.rng | 26 ++++
docs/sitemap.html.in | 4 +
libvirt.spec.in | 1 +
mingw-libvirt.spec.in | 2 +
src/Makefile.am | 3 +-
src/conf/viremulator_capabilities.c | 139 +++++++++++++++++++++
src/conf/viremulator_capabilities.h | 47 +++++++
src/libvirt_private.syms | 6 +
tests/Makefile.am | 10 +-
.../viremulatorcaps-basic.xml | 5 +
tests/viremulatorcapabilitiesschematest | 11 ++
tests/viremulatorcapabilitiestest.c | 117 +++++++++++++++++
14 files changed, 422 insertions(+), 2 deletions(-)
create mode 100644 docs/formatemulatorcaps.html.in
create mode 100644 docs/schemas/emulatorcapability.rng
create mode 100644 src/conf/viremulator_capabilities.c
create mode 100644 src/conf/viremulator_capabilities.h
create mode 100644 tests/viremulatorcapabilitiesdata/viremulatorcaps-basic.xml
create mode 100755 tests/viremulatorcapabilitiesschematest
create mode 100644 tests/viremulatorcapabilitiestest.c
diff --git a/docs/formatemulatorcaps.html.in b/docs/formatemulatorcaps.html.in
new file mode 100644
index 0000000..beea1a9
--- /dev/null
+++ b/docs/formatemulatorcaps.html.in
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html
xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <h1>Emulator capabilities XML format</h1>
+
+ <ul id="toc"></ul>
+
+ <h2><a name="Motivation">Motivation</a></h2>
+
+ <p>Sometimes, when a new domain is to be created it may come handy to know
+ the capabilities of the hypervisor so the correct combination of devices and
+ drivers is used. For example, when management application is considering the
+ mode for a host device's passthrough there are several options depending not
+ only on host, but on hypervisor in question too. If the hypervisor is qemu
+ then it needs to be more recent to support VFIO, while legacy KVM is
+ achievable just fine with older one.</p>
+
+ <p>The main difference between <a
+ href="formatcaps.html">virConnectGetCapabilities</a> and the
emulator
+ capabilities API is, the former one aims more on the host capabilities (e.g.
+ NUMA topology, security models in effect, etc.) while the latter one
+ specializes on the hypervisor capabilities.</p>
+
+ <h2><a name="elements">Element and attribute
overview</a></h2>
+
+ <p>The root element that emulator capability XML document starts with has
+ name <code>emulatorCapabilities</code>. It contains at least three
direct
+ child elements:</p>
+
+<pre>
+<emulatorCapabilities>
+ <path>/usr/bin/qemu-system-x86_64</path>
+ <domain>kvm</domain>
+ <machine>pc-i440fx-2.1</machine>
+ ...
+</emulatorCapabilities>
+</pre>
+ <dl>
+ <dt>path</dt>
+ <dd>The full path to the emulator binary.</dd>
+
+ <dt>domain</dt>
+ <dd>Describes the <a
href="formatdomain.html#elements">virtualization
+ type</a> (or so called domain type).</dd>
+
+ <dt>machine</dt>
+ <dd>The domain's <a
href="formatdomain.html#elementsOSBIOS">machine
+ type</a>.</dd>
+ </dl>
+ </body>
+</html>
diff --git a/docs/schemas/Makefile.am b/docs/schemas/Makefile.am
index d71c327..3072f4f 100644
--- a/docs/schemas/Makefile.am
+++ b/docs/schemas/Makefile.am
@@ -21,6 +21,7 @@ schema_DATA = \
domain.rng \
domaincommon.rng \
domainsnapshot.rng \
+ emulatorcapability.rng \
interface.rng \
network.rng \
networkcommon.rng \
diff --git a/docs/schemas/emulatorcapability.rng b/docs/schemas/emulatorcapability.rng
new file mode 100644
index 0000000..2548cef
--- /dev/null
+++ b/docs/schemas/emulatorcapability.rng
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!-- A Relax NG schema for the libvirt capabilities XML format -->
+<grammar
xmlns="http://relaxng.org/ns/structure/1.0"
+
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+ <include href='basictypes.rng'/>
+ <start>
+ <ref name='emulatorCapabilities'/>
+ </start>
+
+
+ <define name='emulatorCapabilities'>
+ <element name='emulatorCapabilities'>
+ <interleave>
+ <element name='path'>
+ <ref name="absFilePath"/>
+ </element>
+ <element name='domain'>
+ <text/>
+ </element>
+ <element name='machine'>
+ <text/>
+ </element>
+ </interleave>
+ </element>
+ </define>
+</grammar>
diff --git a/docs/sitemap.html.in b/docs/sitemap.html.in
index 78e84e3..6ed4e4d 100644
--- a/docs/sitemap.html.in
+++ b/docs/sitemap.html.in
@@ -175,6 +175,10 @@
<span>The driver capabilities XML format</span>
</li>
<li>
+ <a href="formatemulatorcaps.html">Emulator
capabilities</a>
+ <span>The emulator capabilities XML format</span>
+ </li>
+ <li>
<a href="formatnode.html">Node Devices</a>
<span>The host device XML format</span>
</li>
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 344748c..2545503 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -2164,6 +2164,7 @@ exit 0
%{_datadir}/libvirt/schemas/domain.rng
%{_datadir}/libvirt/schemas/domaincommon.rng
%{_datadir}/libvirt/schemas/domainsnapshot.rng
+%{_datadir}/libvirt/schemas/emulatorcapability.rng
%{_datadir}/libvirt/schemas/interface.rng
%{_datadir}/libvirt/schemas/network.rng
%{_datadir}/libvirt/schemas/networkcommon.rng
diff --git a/mingw-libvirt.spec.in b/mingw-libvirt.spec.in
index 1b505e6..ca1db40 100644
--- a/mingw-libvirt.spec.in
+++ b/mingw-libvirt.spec.in
@@ -205,6 +205,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
%{mingw32_datadir}/libvirt/schemas/domain.rng
%{mingw32_datadir}/libvirt/schemas/domaincommon.rng
%{mingw32_datadir}/libvirt/schemas/domainsnapshot.rng
+%{mingw32_datadir}/libvirt/schemas/emulatorcapability.rng
%{mingw32_datadir}/libvirt/schemas/interface.rng
%{mingw32_datadir}/libvirt/schemas/network.rng
%{mingw32_datadir}/libvirt/schemas/networkcommon.rng
@@ -265,6 +266,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
%{mingw64_datadir}/libvirt/schemas/domain.rng
%{mingw64_datadir}/libvirt/schemas/domaincommon.rng
%{mingw64_datadir}/libvirt/schemas/domainsnapshot.rng
+%{mingw64_datadir}/libvirt/schemas/emulatorcapability.rng
%{mingw64_datadir}/libvirt/schemas/interface.rng
%{mingw64_datadir}/libvirt/schemas/network.rng
%{mingw64_datadir}/libvirt/schemas/networkcommon.rng
diff --git a/src/Makefile.am b/src/Makefile.am
index 2b9ac61..9db896d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -251,7 +251,8 @@ DOMAIN_CONF_SOURCES = \
conf/domain_conf.c conf/domain_conf.h \
conf/domain_audit.c conf/domain_audit.h \
conf/domain_nwfilter.c conf/domain_nwfilter.h \
- conf/snapshot_conf.c conf/snapshot_conf.h
+ conf/snapshot_conf.c conf/snapshot_conf.h \
+ conf/viremulator_capabilities.c conf/viremulator_capabilities.h
OBJECT_EVENT_SOURCES = \
conf/object_event.c conf/object_event.h \
diff --git a/src/conf/viremulator_capabilities.c b/src/conf/viremulator_capabilities.c
new file mode 100644
index 0000000..8e7d4af
--- /dev/null
+++ b/src/conf/viremulator_capabilities.c
@@ -0,0 +1,139 @@
+/*
+ * viremulator_capabilities.c: hypervisor capabilities
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author: Michal Privoznik <mprivozn(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include "viremulator_capabilities.h"
+#include "virobject.h"
+#include "viralloc.h"
+#include "virbuffer.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_CAPABILITIES
+
+struct _virEmulatorCapabilities {
+ virObjectLockable parent;
+
+ char *path; /* path to emulator binary */
+ char *machine; /* machine type */
+ virDomainVirtType virttype; /* virtualization type */
+
+ void *privateData;
+ virEmulatorCapabilitiesPrivateDataFormatFunc formatFunc;
+};
+
+static virClassPtr virEmulatorCapabilitiesClass;
+
+static void virEmulatorCapabilitiesDispose(void *obj);
+
+static int virEmulatorCapabilitiesOnceInit(void)
+{
+ if (!(virEmulatorCapabilitiesClass = virClassNew(virClassForObjectLockable(),
+
"virEmulatorCapabilities",
+ sizeof(virEmulatorCapabilities),
+ virEmulatorCapabilitiesDispose)))
+ return -1;
+
+ return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virEmulatorCapabilities)
+
+
+static void
+virEmulatorCapabilitiesDispose(void *obj)
+{
+ virEmulatorCapabilitiesPtr caps = obj;
+
+ VIR_FREE(caps->path);
+ VIR_FREE(caps->machine);
+}
+
+
+virEmulatorCapabilitiesPtr
+virEmulatorCapabilitiesNew(const char *path,
+ const char *machine,
+ virDomainVirtType virttype)
+{
+ virEmulatorCapabilitiesPtr caps = NULL;
+
+ if (virEmulatorCapabilitiesInitialize() < 0)
+ return NULL;
+
+ if (!(caps = virObjectLockableNew(virEmulatorCapabilitiesClass)))
+ return NULL;
+
+ if (VIR_STRDUP(caps->path, path) < 0 ||
+ VIR_STRDUP(caps->machine, machine) < 0)
+ goto error;
+ caps->virttype = virttype;
+
+ return caps;
+ error:
+ virObjectUnref(caps);
+ return NULL;
+}
+
+
+void
+virEmulatorCapabilitiesSetPrivate(virEmulatorCapabilitiesPtr caps,
+ void *privateData,
+ virEmulatorCapabilitiesPrivateDataFormatFunc
formatFunc)
+{
+ if (!caps)
+ return;
+
+ caps->privateData = privateData;
+ caps->formatFunc = formatFunc;
+}
+
+
+static int
+virEmulatorCapabilitiesFormatInternal(virEmulatorCapabilitiesPtr caps,
+ virBufferPtr buf)
+{
+ const char *virttype_str = virDomainVirtTypeToString(caps->virttype);
+
+ virBufferAddLit(buf, "<emulatorCapabilities>\n");
+ virBufferAdjustIndent(buf, 2);
+ virBufferAsprintf(buf, "<path>%s</path>\n", caps->path);
+ virBufferAsprintf(buf, "<domain>%s</domain>\n", virttype_str);
+ virBufferAsprintf(buf, "<machine>%s</machine>\n",
caps->machine);
+ if (caps->formatFunc)
+ caps->formatFunc(buf, caps->privateData, caps->machine);
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</emulatorCapabilities>\n");
+ return 0;
+}
+
+
+char *
+virEmulatorCapabilitiesFormat(virEmulatorCapabilitiesPtr caps)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (virEmulatorCapabilitiesFormatInternal(caps, &buf) < 0)
+ return NULL;
+
+ return virBufferContentAndReset(&buf);
+
+}
diff --git a/src/conf/viremulator_capabilities.h b/src/conf/viremulator_capabilities.h
new file mode 100644
index 0000000..361f765
--- /dev/null
+++ b/src/conf/viremulator_capabilities.h
@@ -0,0 +1,47 @@
+/*
+ * viremulator_capabilities.h: hypervisor capabilities
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author: Michal Privoznik <mprivozn(a)redhat.com>
+ */
+
+#ifndef __VIR_EMULATOR_CAPABILITIES_H
+# define __VIR_EMULATOR_CAPABILITIES_H
+
+# include "domain_conf.h"
+
+typedef int
+(*virEmulatorCapabilitiesPrivateDataFormatFunc)(virBufferPtr buf,
+ void *privateData,
+ const char *machine);
+
+typedef struct _virEmulatorCapabilities virEmulatorCapabilities;
+typedef virEmulatorCapabilities *virEmulatorCapabilitiesPtr;
+
+virEmulatorCapabilitiesPtr
+virEmulatorCapabilitiesNew(const char *path,
+ const char *machine,
+ virDomainVirtType virttype);
+
+void
+virEmulatorCapabilitiesSetPrivate(virEmulatorCapabilitiesPtr caps,
+ void *privateData,
+ virEmulatorCapabilitiesPrivateDataFormatFunc
formatFunc);
+
+char *virEmulatorCapabilitiesFormat(virEmulatorCapabilitiesPtr caps);
+#endif
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1d29f15..2784610 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -759,6 +759,12 @@ virChrdevFree;
virChrdevOpen;
+# conf/viremulator_capabilities.h
+virEmulatorCapabilitiesFormat;
+virEmulatorCapabilitiesNew;
+virEmulatorCapabilitiesSetPrivate;
+
+
# cpu/cpu.h
cpuBaseline;
cpuBaselineXML;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c999061..e7d9f94 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -125,6 +125,8 @@ EXTRA_DIST = \
sysinfodata \
test-lib.sh \
vircaps2xmldata \
+ viremulatorcapabilitiesdata\
+ viremulatorcapabilitiesschematest \
vboxsnapshotxmldata \
virsh-uriprecedence \
virfiledata \
@@ -167,6 +169,7 @@ test_programs = virshtest sockettest \
virnetdevbandwidthtest \
virkmodtest \
vircapstest \
+ viremulatorcapabilitiestest \
domainconftest \
virhostdevtest \
vircaps2xmltest \
@@ -319,7 +322,8 @@ test_scripts = \
nodedevschematest \
nwfilterschematest \
domainsnapshotschematest \
- secretschematest
+ secretschematest \
+ viremulatorcapabilitiesschematest
if WITH_LIBVIRTD
test_scripts += \
@@ -824,6 +828,10 @@ vircaps2xmltest_SOURCES = \
vircaps2xmltest.c testutils.h testutils.c
vircaps2xmltest_LDADD = $(LDADDS)
+viremulatorcapabilitiestest_SOURCES = \
+ viremulatorcapabilitiestest.c testutils.h testutils.c
+viremulatorcapabilitiestest_LDADD = $(LDADDS)
+
if WITH_LIBVIRTD
libvirtdconftest_SOURCES = \
libvirtdconftest.c testutils.h testutils.c \
diff --git a/tests/viremulatorcapabilitiesdata/viremulatorcaps-basic.xml
b/tests/viremulatorcapabilitiesdata/viremulatorcaps-basic.xml
new file mode 100644
index 0000000..a3fd457
--- /dev/null
+++ b/tests/viremulatorcapabilitiesdata/viremulatorcaps-basic.xml
@@ -0,0 +1,5 @@
+<emulatorCapabilities>
+ <path>/bin/emulatorbin</path>
+ <domain>uml</domain>
+ <machine>my-machine-type</machine>
+</emulatorCapabilities>
diff --git a/tests/viremulatorcapabilitiesschematest
b/tests/viremulatorcapabilitiesschematest
new file mode 100755
index 0000000..e4dd621
--- /dev/null
+++ b/tests/viremulatorcapabilitiesschematest
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+: ${srcdir=.}
+. $srcdir/test-lib.sh
+. $abs_srcdir/schematestutils.sh
+
+DIRS=""
+DIRS="$DIRS viremulatorcapabilitiesdata"
+SCHEMA="emulatorcapability.rng"
+
+check_schema "$DIRS" "$SCHEMA"
diff --git a/tests/viremulatorcapabilitiestest.c b/tests/viremulatorcapabilitiestest.c
new file mode 100644
index 0000000..448f0cf
--- /dev/null
+++ b/tests/viremulatorcapabilitiestest.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) Red Hat, Inc. 2014
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Michal Privoznik <mprivozn(a)redhat.com>
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include "testutils.h"
+#include "viremulator_capabilities.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+static virEmulatorCapabilitiesPtr
+buildVirEmulatorCapabilities(const char *emulatorbin,
+ const char *machine,
+ virDomainVirtType type,
+ void *privateData,
+ virEmulatorCapabilitiesPrivateDataFormatFunc formatFunc)
+{
+ virEmulatorCapabilitiesPtr emulCaps;
+
+ if (!(emulCaps = virEmulatorCapabilitiesNew(emulatorbin, machine, type)))
+ goto cleanup;
+
+ if (privateData)
+ virEmulatorCapabilitiesSetPrivate(emulCaps, privateData, formatFunc);
+
+ cleanup:
+ return emulCaps;
+}
+
+struct test_virEmulatorCapabilitiesFormatData {
+ const char *filename;
+ const char *emulatorbin;
+ const char *machine;
+ virDomainVirtType type;
+ void *privateData;
+ virEmulatorCapabilitiesPrivateDataFormatFunc formatFunc;
+};
+
+static int
+test_virEmulatorCapabilitiesFormat(const void *opaque)
+{
+ struct test_virEmulatorCapabilitiesFormatData *data =
+ (struct test_virEmulatorCapabilitiesFormatData *) opaque;
+ virEmulatorCapabilitiesPtr emulCaps = NULL;
+ char *path = NULL;
+ char *emulCapsXML = NULL;
+ char *emulCapsFromFile = NULL;
+ int ret = -1;
+
+ if (virAsprintf(&path,
"%s/viremulatorcapabilitiesdata/viremulatorcaps-%s.xml",
+ abs_srcdir, data->filename) < 0)
+ goto cleanup;
+
+ if (virFileReadAll(path, 8192, &emulCapsFromFile) < 0)
+ goto cleanup;
+
+ if (!(emulCaps = buildVirEmulatorCapabilities(data->emulatorbin,
data->machine,
+ data->type, data->privateData,
+ data->formatFunc)))
+ goto cleanup;
+
+ if (!(emulCapsXML = virEmulatorCapabilitiesFormat(emulCaps)))
+ goto cleanup;
+
+ if (STRNEQ(emulCapsFromFile, emulCapsXML)) {
+ virtTestDifference(stderr, emulCapsFromFile, emulCapsXML);
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(emulCapsFromFile);
+ VIR_FREE(emulCapsXML);
+ VIR_FREE(path);
+ virObjectUnref(emulCaps);
+ return ret;
+}
+
+static int
+mymain(void)
+{
+ int ret = 0;
+
+#define DO_TEST(Filename, Emulatorbin, Machine, Type, ...) \
+ do { \
+ struct test_virEmulatorCapabilitiesFormatData data = {.filename = Filename, \
+ .emulatorbin = Emulatorbin, .machine = Machine, .type = Type, __VA_ARGS__};
\
+ if (virtTestRun(Filename, test_virEmulatorCapabilitiesFormat, &data) < 0)
\
+ ret = -1; \
+ } while (0)
+
+ DO_TEST("basic", "/bin/emulatorbin", "my-machine-type",
VIR_DOMAIN_VIRT_UML);
+
+ return ret;
+}
+
+VIRT_TEST_MAIN(mymain)
--
1.8.5.5