The virDomainDefineXMLFlags and virDomainCreateXML APIs both
gain new flags allowing them to be told to validate XML.
The main limitation with this is that libxml2's errors for
failing schema validation are really awful and not likely
to be any help for the user
eg, I added an element <foo>bar</foo> immediately below
the <domain> element and got this:
$ virsh define --validate ppcdemo.xml
error: Failed to define domain from ppcdemo.xml
error: XML document failed to validate against schema: Unable to validate doc against
/usr/share/libvirt/schemas/domain.rng
Expecting an element os, got nothing
Invalid sequence in interleave
Invalid sequence in interleave
Element domain failed to validate content
Either libxml2 would have to dramatically improve its
error reporting, or we'd have to look at a different
library for schema validation.
---
include/libvirt/libvirt-domain.h | 5 +++++
src/conf/domain_conf.c | 6 ++++++
src/conf/domain_conf.h | 1 +
src/qemu/qemu_driver.c | 16 ++++++++++++----
tools/virsh-domain.c | 19 ++++++++++++++++++-
5 files changed, 42 insertions(+), 5 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 864c16c..8ce2f68 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -273,6 +273,7 @@ typedef enum {
VIR_DOMAIN_START_AUTODESTROY = 1 << 1, /* Automatically kill guest when
virConnectPtr is closed */
VIR_DOMAIN_START_BYPASS_CACHE = 1 << 2, /* Avoid file system cache pollution
*/
VIR_DOMAIN_START_FORCE_BOOT = 1 << 3, /* Boot, discarding any managed save
*/
+ VIR_DOMAIN_START_VALIDATE = 1 << 4, /* Validate the XML document against
schema */
} virDomainCreateFlags;
@@ -1410,6 +1411,10 @@ int virDomainMemoryPeek (virDomainPtr dom,
void *buffer,
unsigned int flags);
+typedef enum {
+ VIR_DOMAIN_DEFINE_VALIDATE = (1 << 0), /* Validate the XML document against
schema */
+} virDomainDefineFlags;
+
/*
* defined but not running domains
*/
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 2dace76..9218df8 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -29,6 +29,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "configmake.h"
#include "internal.h"
#include "virerror.h"
#include "datatypes.h"
@@ -12171,6 +12172,11 @@ virDomainDefParseXML(xmlDocPtr xml,
bool usb_master = false;
bool primaryVideo = false;
+ if ((flags & VIR_DOMAIN_DEF_PARSE_VALIDATE) &&
+ virXMLValidateAgainstSchema(PKGDATADIR "/schemas/domain.rng",
+ xml) < 0)
+ return NULL;
+
if (VIR_ALLOC(def) < 0)
return NULL;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 98497d6..df9789a 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2402,6 +2402,7 @@ typedef enum {
VIR_DOMAIN_DEF_PARSE_CLOCK_ADJUST = 1 << 7,
/* parse only source half of <disk> */
VIR_DOMAIN_DEF_PARSE_DISK_SOURCE = 1 << 8,
+ VIR_DOMAIN_DEF_PARSE_VALIDATE = 1 << 9,
} virDomainDefParseFlags;
typedef enum {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6ccf940..48e7e75 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1689,10 +1689,14 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn,
unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;
virQEMUCapsPtr qemuCaps = NULL;
virCapsPtr caps = NULL;
+ unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
virCheckFlags(VIR_DOMAIN_START_PAUSED |
- VIR_DOMAIN_START_AUTODESTROY, NULL);
+ VIR_DOMAIN_START_AUTODESTROY |
+ VIR_DOMAIN_START_VALIDATE, NULL);
+ if (flags & VIR_DOMAIN_START_VALIDATE)
+ parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
if (flags & VIR_DOMAIN_START_PAUSED)
start_flags |= VIR_QEMU_PROCESS_START_PAUSED;
if (flags & VIR_DOMAIN_START_AUTODESTROY)
@@ -1705,7 +1709,7 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn,
if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
QEMU_EXPECTED_VIRT_TYPES,
- VIR_DOMAIN_DEF_PARSE_INACTIVE)))
+ parse_flags)))
goto cleanup;
if (virDomainCreateXMLEnsureACL(conn, def) < 0)
@@ -6662,8 +6666,12 @@ static virDomainPtr qemuDomainDefineXMLFlags(virConnectPtr conn,
const char *xml
virQEMUCapsPtr qemuCaps = NULL;
virQEMUDriverConfigPtr cfg;
virCapsPtr caps = NULL;
+ unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
- virCheckFlags(0, NULL);
+ virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
+
+ if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
+ parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
cfg = virQEMUDriverGetConfig(driver);
@@ -6672,7 +6680,7 @@ static virDomainPtr qemuDomainDefineXMLFlags(virConnectPtr conn,
const char *xml
if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
QEMU_EXPECTED_VIRT_TYPES,
- VIR_DOMAIN_DEF_PARSE_INACTIVE)))
+ parse_flags)))
goto cleanup;
if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index a7e9151..876fd4b 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -7163,6 +7163,10 @@ static const vshCmdOptDef opts_define[] = {
.flags = VSH_OFLAG_REQ,
.help = N_("file containing an XML domain description")
},
+ {.name = "skip-validate",
+ .type = VSH_OT_BOOL,
+ .help = N_("skip validation of the XML against the schema")
+ },
{.name = NULL}
};
@@ -7173,14 +7177,27 @@ cmdDefine(vshControl *ctl, const vshCmd *cmd)
const char *from = NULL;
bool ret = true;
char *buffer;
+ unsigned int flags = VIR_DOMAIN_DEFINE_VALIDATE;
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
return false;
+ if (vshCommandOptBool(cmd, "skip-validate"))
+ flags &= ~VIR_DOMAIN_DEFINE_VALIDATE;
+
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
return false;
- dom = virDomainDefineXML(ctl->conn, buffer);
+ if (flags) {
+ dom = virDomainDefineXMLFlags(ctl->conn, buffer, flags);
+ if (!dom) {
+ virErrorPtr err = virGetLastError();
+ if (err && err->code == VIR_ERR_NO_SUPPORT)
+ dom = virDomainDefineXML(ctl->conn, buffer);
+ }
+ } else {
+ dom = virDomainDefineXML(ctl->conn, buffer);
+ }
VIR_FREE(buffer);
if (dom != NULL) {
--
2.1.0