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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list