Add new parameter to virDomainObjListLoadConfig() and
virDomainObjListLoadAllConfigs() that controls whether domains with
invalid XML (which could not be parsed) should be kept in order not to
lose track of them. For now, the parameter is set to false in all
callers. Each driver can switch it to true when it is prepared to deal
with such domains.
For the domain object to be created add virDomainDefParseMinimal() that
parses only name and UUID from the XML definition. UUID must be
present, it will not be generated. The purpose of this function is to
be used when all else fails, but we still want a domain object to work
with.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/bhyve/bhyve_driver.c | 2 +
src/conf/domain_conf.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++--
src/conf/domain_conf.h | 5 +++
src/libxl/libxl_driver.c | 3 ++
src/lxc/lxc_driver.c | 3 ++
src/qemu/qemu_driver.c | 3 ++
src/uml/uml_driver.c | 2 +
7 files changed, 109 insertions(+), 4 deletions(-)
diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c
index 7f365b1f2446..abf6789c2f9c 100644
--- a/src/bhyve/bhyve_driver.c
+++ b/src/bhyve/bhyve_driver.c
@@ -1219,6 +1219,7 @@ bhyveStateInitialize(bool privileged,
NULL, 1,
bhyve_driver->caps,
bhyve_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto cleanup;
@@ -1227,6 +1228,7 @@ bhyveStateInitialize(bool privileged,
BHYVE_AUTOSTART_DIR, 0,
bhyve_driver->caps,
bhyve_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto cleanup;
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 230800542f8c..6850e79396bb 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -22676,6 +22676,39 @@ virDomainSaveStatus(virDomainXMLOptionPtr xmlopt,
return ret;
}
+static virDomainDefPtr
+virDomainDefParseMinimal(const char *filename,
+ const char *xmlStr)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ virDomainDefPtr def = NULL;
+ xmlDocPtr xml = NULL;
+
+ if (!(xml = virXMLParse(filename, xmlStr, _("(domain_definition)"))))
+ goto cleanup;
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = xmlDocGetRootElement(xml);
+
+ if (!(def = virDomainDefNew()))
+ goto cleanup;
+
+ def->id = -1;
+
+ if (virDomainDefParseName(def, ctxt) < 0 ||
+ virDomainDefParseUUID(def, ctxt, true, NULL) < 0)
+ virDomainDefFree(def);
+
+ cleanup:
+ xmlFreeDoc(xml);
+ xmlXPathFreeContext(ctxt);
+ return def;
+}
static virDomainObjPtr
virDomainObjListLoadConfig(virDomainObjListPtr doms,
@@ -22684,6 +22717,7 @@ virDomainObjListLoadConfig(virDomainObjListPtr doms,
const char *configDir,
const char *autostartDir,
const char *name,
+ bool keep_invalid,
virDomainLoadConfigNotify notify,
void *opaque)
{
@@ -22692,13 +22726,57 @@ virDomainObjListLoadConfig(virDomainObjListPtr doms,
virDomainObjPtr dom;
int autostart;
virDomainDefPtr oldDef = NULL;
+ char *xmlStr = NULL;
+ char *xmlErr = NULL;
if ((configFile = virDomainConfigFile(configDir, name)) == NULL)
goto error;
- if (!(def = virDomainDefParseFile(configFile, caps, xmlopt,
- VIR_DOMAIN_DEF_PARSE_INACTIVE |
- VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS)))
- goto error;
+
+ def = virDomainDefParseFile(configFile, caps, xmlopt,
+ VIR_DOMAIN_DEF_PARSE_INACTIVE |
+ VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS);
+ if (!def) {
+ char *tmp = NULL;
+
+ if (!keep_invalid)
+ goto error;
+
+ if (VIR_STRDUP(xmlErr, virGetLastErrorMessage()) < 0)
+ goto error;
+
+ if (virFileReadAll(configFile, 1024*1024*10, &xmlStr) < 0)
+ goto error;
+
+ if (!(def = virDomainDefParseMinimal(NULL, xmlStr)))
+ goto error;
+
+ /*
+ * Remove the comment with a warning from the top. Don't fail
+ * if we can't copy it or find it.
+ */
+ tmp = strstr(xmlStr, "-->");
+
+ if (tmp)
+ tmp += strlen("-->");
+ else
+ tmp = xmlStr;
+
+ if (virAsprintf(&def->xmlStr,
+ "<!-- %s\n\n%s\n-->%s",
+ _("WARNING: The following XML failed to load!"
+ "\n\n"
+ "In order for it to be loaded properly, "
+ "it needs to be fixed.\n"
+ "The error that was reported while loading "
+ "is provided below for your convenience:"),
+ xmlErr, tmp) < 0) {
+ def->xmlStr = xmlStr;
+ xmlStr = NULL;
+ }
+
+ def->parseError = xmlErr;
+ xmlErr = NULL;
+ }
if ((autostartLink = virDomainConfigFile(autostartDir, name)) == NULL)
goto error;
@@ -22711,6 +22789,11 @@ virDomainObjListLoadConfig(virDomainObjListPtr doms,
dom->autostart = autostart;
+ if (def->parseError) {
+ virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF,
+ VIR_DOMAIN_SHUTOFF_INVALID_XML);
+ }
+
if (notify)
(*notify)(dom, oldDef == NULL, opaque);
@@ -22720,6 +22803,8 @@ virDomainObjListLoadConfig(virDomainObjListPtr doms,
return dom;
error:
+ VIR_FREE(xmlErr);
+ VIR_FREE(xmlStr);
VIR_FREE(configFile);
VIR_FREE(autostartLink);
virDomainDefFree(def);
@@ -22790,6 +22875,7 @@ virDomainObjListLoadAllConfigs(virDomainObjListPtr doms,
int liveStatus,
virCapsPtr caps,
virDomainXMLOptionPtr xmlopt,
+ bool keep_invalid,
virDomainLoadConfigNotify notify,
void *opaque)
{
@@ -22837,6 +22923,7 @@ virDomainObjListLoadAllConfigs(virDomainObjListPtr doms,
configDir,
autostartDir,
entry->d_name,
+ keep_invalid,
notify,
opaque);
if (dom) {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 8be390b7811a..fa6449461047 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2195,6 +2195,10 @@ struct _virDomainDef {
char *title;
char *description;
+ /* Possible error and string that failed parsing */
+ char *xmlStr;
+ const char *parseError;
+
virDomainBlkiotune blkio;
virDomainMemtune mem;
@@ -2897,6 +2901,7 @@ int virDomainObjListLoadAllConfigs(virDomainObjListPtr doms,
int liveStatus,
virCapsPtr caps,
virDomainXMLOptionPtr xmlopt,
+ bool keep_invalid,
virDomainLoadConfigNotify notify,
void *opaque);
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 8087c2779795..53ea64b9bdd1 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -694,6 +694,7 @@ libxlStateInitialize(bool privileged,
1,
cfg->caps,
libxl_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto error;
@@ -706,6 +707,7 @@ libxlStateInitialize(bool privileged,
0,
cfg->caps,
libxl_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto error;
@@ -746,6 +748,7 @@ libxlStateReload(void)
1,
cfg->caps,
libxl_driver->xmlopt,
+ false,
NULL, libxl_driver);
virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 71be9c7de8a6..e185d785de8c 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1659,6 +1659,7 @@ static int lxcStateInitialize(bool privileged,
NULL, 1,
caps,
lxc_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto cleanup;
@@ -1670,6 +1671,7 @@ static int lxcStateInitialize(bool privileged,
cfg->autostartDir, 0,
caps,
lxc_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto cleanup;
@@ -1734,6 +1736,7 @@ lxcStateReload(void)
cfg->autostartDir, 0,
caps,
lxc_driver->xmlopt,
+ false,
lxcNotifyLoadDomain, lxc_driver);
virObjectUnref(caps);
virObjectUnref(cfg);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 8197f0238fb7..e7b47eaa944c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -902,6 +902,7 @@ qemuStateInitialize(bool privileged,
NULL, 1,
qemu_driver->caps,
qemu_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto error;
@@ -924,6 +925,7 @@ qemuStateInitialize(bool privileged,
cfg->autostartDir, 0,
qemu_driver->caps,
qemu_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto error;
@@ -1004,6 +1006,7 @@ qemuStateReload(void)
cfg->configDir,
cfg->autostartDir, 0,
caps, qemu_driver->xmlopt,
+ false,
qemuNotifyLoadDomain, qemu_driver);
cleanup:
virObjectUnref(cfg);
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index c3c5fa7d9ac5..cb652838fe19 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -578,6 +578,7 @@ umlStateInitialize(bool privileged,
uml_driver->autostartDir, 0,
uml_driver->caps,
uml_driver->xmlopt,
+ false,
NULL, NULL) < 0)
goto error;
@@ -646,6 +647,7 @@ umlStateReload(void)
uml_driver->autostartDir, 0,
uml_driver->caps,
uml_driver->xmlopt,
+ false,
umlNotifyLoadDomain, uml_driver);
umlDriverUnlock(uml_driver);
--
2.5.3