The 'virsh define', 'virsh create' and 'virsh edit' commands
get XML validation enabled by default, with a --skip-validate
option to disable it.
The quality of error reporting from libxml2 varies depending
on the type of XML error made. Sometimes it is quite clear
and useful, other times it is obscure & inaccurate. At least
the user will see an error now, rather than having their
XML modification silently disappear.
---
tests/cpuset | 2 +-
tools/virsh-domain.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 79 insertions(+), 10 deletions(-)
diff --git a/tests/cpuset b/tests/cpuset
index 35803be..7b8d668 100755
--- a/tests/cpuset
+++ b/tests/cpuset
@@ -39,7 +39,7 @@ grep '<vcpu placement' xml > /dev/null || fail=1
sed "s/vcpu placement='static'>/vcpu cpuset='aaa'>/" xml
> xml-invalid || fail=1
# Require failure and a diagnostic.
-$abs_top_builddir/tools/virsh --connect test:///default define xml-invalid > out
2>&1 && fail=1
+$abs_top_builddir/tools/virsh --connect test:///default define --skip-validate
xml-invalid > out 2>&1 && fail=1
cat <<\EOF > exp || fail=1
error: Failed to define domain from xml-invalid
error: invalid argument: Failed to parse bitmap 'aaa'
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 750411b..a652942 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -133,6 +133,56 @@ vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
return vshLookupDomainInternal(ctl, cmd->def->name, n, flags);
}
+static virDomainPtr
+vshDomainDefine(virConnectPtr conn, const char *xml, unsigned int flags)
+{
+ virDomainPtr dom;
+ if (flags) {
+ dom = virDomainDefineXMLFlags(conn, xml, flags);
+ /* If validate is the only flag, just drop it and
+ * try again.
+ */
+ if (!dom) {
+ virErrorPtr err = virGetLastError();
+ if (err &&
+ (err->code == VIR_ERR_NO_SUPPORT) &&
+ (flags == VIR_DOMAIN_DEFINE_VALIDATE))
+ dom = virDomainDefineXML(conn, xml);
+ }
+ } else {
+ dom = virDomainDefineXML(conn, xml);
+ }
+ return dom;
+}
+
+
+static virDomainPtr
+vshDomainCreateXML(virConnectPtr conn, const char *xml,
+ size_t nfds, int *fds, unsigned int flags)
+{
+ virDomainPtr dom;
+ if (nfds)
+ dom = virDomainCreateXMLWithFiles(conn, xml,
+ nfds, fds, flags);
+ else
+ dom = virDomainCreateXML(conn, xml, flags);
+ /* If validate is set, just drop it and try again */
+ if (!dom) {
+ virErrorPtr err = virGetLastError();
+ if (err &&
+ (err->code == VIR_ERR_INVALID_ARG) &&
+ (flags & VIR_DOMAIN_START_VALIDATE)) {
+ flags &= ~VIR_DOMAIN_START_VALIDATE;
+ if (nfds)
+ dom = virDomainCreateXMLWithFiles(conn, xml,
+ nfds, fds, flags);
+ else
+ dom = virDomainCreateXML(conn, xml, flags);
+ }
+ }
+ return dom;
+}
+
VIR_ENUM_DECL(vshDomainVcpuState)
VIR_ENUM_IMPL(vshDomainVcpuState,
VIR_VCPU_LAST,
@@ -7154,6 +7204,10 @@ static const vshCmdOptDef opts_create[] = {
.type = VSH_OT_STRING,
.help = N_("pass file descriptors N,M,... to the guest")
},
+ {.name = "skip-validate",
+ .type = VSH_OT_BOOL,
+ .help = N_("skip validation of the XML against the schema")
+ },
{.name = NULL}
};
@@ -7167,7 +7221,7 @@ cmdCreate(vshControl *ctl, const vshCmd *cmd)
#ifndef WIN32
bool console = vshCommandOptBool(cmd, "console");
#endif
- unsigned int flags = VIR_DOMAIN_NONE;
+ unsigned int flags = VIR_DOMAIN_START_VALIDATE;
size_t nfds = 0;
int *fds = NULL;
@@ -7184,11 +7238,10 @@ cmdCreate(vshControl *ctl, const vshCmd *cmd)
flags |= VIR_DOMAIN_START_PAUSED;
if (vshCommandOptBool(cmd, "autodestroy"))
flags |= VIR_DOMAIN_START_AUTODESTROY;
+ if (vshCommandOptBool(cmd, "skip-validate"))
+ flags &= ~VIR_DOMAIN_DEFINE_VALIDATE;
- if (nfds)
- dom = virDomainCreateXMLWithFiles(ctl->conn, buffer, nfds, fds, flags);
- else
- dom = virDomainCreateXML(ctl->conn, buffer, flags);
+ dom = vshDomainCreateXML(ctl->conn, buffer, nfds, fds, flags);
if (!dom) {
vshError(ctl, _("Failed to create domain from %s"), from);
@@ -7229,6 +7282,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}
};
@@ -7239,14 +7296,18 @@ 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);
+ dom = vshDomainDefine(ctl->conn, buffer, flags);
VIR_FREE(buffer);
if (dom != NULL) {
@@ -11105,6 +11166,10 @@ static const vshCmdOptDef opts_edit[] = {
.flags = VSH_OFLAG_REQ,
.help = N_("domain name, id or uuid")
},
+ {.name = "skip-validate",
+ .type = VSH_OT_BOOL,
+ .help = N_("skip validation of the XML against the schema")
+ },
{.name = NULL}
};
@@ -11114,13 +11179,17 @@ cmdEdit(vshControl *ctl, const vshCmd *cmd)
bool ret = false;
virDomainPtr dom = NULL;
virDomainPtr dom_edited = NULL;
- unsigned int flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_INACTIVE;
+ unsigned int query_flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_INACTIVE;
+ unsigned int define_flags = VIR_DOMAIN_DEFINE_VALIDATE;
dom = vshCommandOptDomain(ctl, cmd, NULL);
if (dom == NULL)
goto cleanup;
-#define EDIT_GET_XML virDomainGetXMLDesc(dom, flags)
+ if (vshCommandOptBool(cmd, "skip-validate"))
+ define_flags &= ~VIR_DOMAIN_DEFINE_VALIDATE;
+
+#define EDIT_GET_XML virDomainGetXMLDesc(dom, query_flags)
#define EDIT_NOT_CHANGED \
do { \
vshPrint(ctl, _("Domain %s XML configuration not changed.\n"), \
@@ -11129,7 +11198,7 @@ cmdEdit(vshControl *ctl, const vshCmd *cmd)
goto edit_cleanup; \
} while (0)
#define EDIT_DEFINE \
- (dom_edited = virDomainDefineXML(ctl->conn, doc_edited))
+ (dom_edited = vshDomainDefine(ctl->conn, doc_edited, define_flags))
#include "virsh-edit.c"
vshPrint(ctl, _("Domain %s XML configuration edited.\n"),
--
2.1.0