When parsing XML, we validate the passed ostype + arch combo against
the detected hypervisor capabilities. This has led to the following
problem:
- Define x86 qemu guest
- qemu is inadvertently removed from the host
- libvirtd is restarted. fails to parse VM config since arch is removed
- 'virsh list --all' is now empty, user is wondering where their VMs went
Add a new internal flag VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS. Use
it when loading VM and snapshot configs from disk.
https://bugzilla.redhat.com/show_bug.cgi?id=1043572
---
src/conf/domain_conf.c | 93 +++++++++++++++++++++++++-----------------------
src/conf/domain_conf.h | 4 +++
src/conf/snapshot_conf.c | 6 ++--
3 files changed, 57 insertions(+), 46 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 8458f5b..860c950 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -14655,61 +14655,64 @@ virDomainDefParseXML(xmlDocPtr xml,
goto error;
}
- if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
+ tmp = virXPathString("string(./os/type[1]/@arch)", ctxt);
+ if (tmp && !(def->os.arch = virArchFromString(tmp))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("no support found for os <type> '%s'"),
- def->os.type);
+ _("Unknown architecture %s"),
+ tmp);
goto error;
}
+ VIR_FREE(tmp);
- tmp = virXPathString("string(./os/type[1]/@arch)", ctxt);
- if (tmp) {
- def->os.arch = virArchFromString(tmp);
- if (!def->os.arch) {
+ def->os.machine = virXPathString("string(./os/type[1]/@machine)",
ctxt);
+
+ if (!(flags & VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS)) {
+ if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unknown architecture %s"),
- tmp);
+ _("no support found for os <type>
'%s'"),
+ def->os.type);
goto error;
}
- VIR_FREE(tmp);
- if (!virCapabilitiesSupportsGuestArch(caps, def->os.arch)) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("No guest options available for arch
'%s'"),
- virArchToString(def->os.arch));
- goto error;
- }
+ if (def->os.arch) {
+ if (!virCapabilitiesSupportsGuestArch(caps, def->os.arch)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("No guest options available for arch
'%s'"),
+ virArchToString(def->os.arch));
+ goto error;
+ }
- if (!virCapabilitiesSupportsGuestOSTypeArch(caps,
- def->os.type,
- def->os.arch)) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("No os type '%s' available for arch
'%s'"),
- def->os.type, virArchToString(def->os.arch));
- goto error;
+ if (!virCapabilitiesSupportsGuestOSTypeArch(caps,
+ def->os.type,
+ def->os.arch)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("No os type '%s' available for arch
'%s'"),
+ def->os.type, virArchToString(def->os.arch));
+ goto error;
+ }
+ } else {
+ def->os.arch =
+ virCapabilitiesDefaultGuestArch(caps,
+ def->os.type,
+
virDomainVirtTypeToString(def->virtType));
+ if (!def->os.arch) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no supported architecture for os type
'%s'"),
+ def->os.type);
+ goto error;
+ }
}
- } else {
- def->os.arch =
- virCapabilitiesDefaultGuestArch(caps,
- def->os.type,
-
virDomainVirtTypeToString(def->virtType));
- if (!def->os.arch) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("no supported architecture for os type
'%s'"),
- def->os.type);
- goto error;
+
+ if (!def->os.machine) {
+ const char *defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
+
def->os.type,
+
def->os.arch,
+
virDomainVirtTypeToString(def->virtType));
+ if (VIR_STRDUP(def->os.machine, defaultMachine) < 0)
+ goto error;
}
}
- def->os.machine = virXPathString("string(./os/type[1]/@machine)",
ctxt);
- if (!def->os.machine) {
- const char *defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
- def->os.type,
- def->os.arch,
-
virDomainVirtTypeToString(def->virtType));
- if (VIR_STRDUP(def->os.machine, defaultMachine) < 0)
- goto error;
- }
/*
* Booting options for different OS types....
@@ -21591,7 +21594,8 @@ virDomainObjListLoadConfig(virDomainObjListPtr doms,
goto error;
if (!(def = virDomainDefParseFile(configFile, caps, xmlopt,
expectedVirtTypes,
- VIR_DOMAIN_DEF_PARSE_INACTIVE)))
+ VIR_DOMAIN_DEF_PARSE_INACTIVE |
+ VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS)))
goto error;
if ((autostartLink = virDomainConfigFile(autostartDir, name)) == NULL)
@@ -21641,7 +21645,8 @@ virDomainObjListLoadStatus(virDomainObjListPtr doms,
VIR_DOMAIN_DEF_PARSE_STATUS |
VIR_DOMAIN_DEF_PARSE_ACTUAL_NET |
VIR_DOMAIN_DEF_PARSE_PCI_ORIG_STATES |
- VIR_DOMAIN_DEF_PARSE_CLOCK_ADJUST)))
+ VIR_DOMAIN_DEF_PARSE_CLOCK_ADJUST |
+ VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS)))
goto error;
virUUIDFormat(obj->def->uuid, uuidstr);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index e6fa3c9..3045652 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2530,6 +2530,10 @@ typedef enum {
/* parse only source half of <disk> */
VIR_DOMAIN_DEF_PARSE_DISK_SOURCE = 1 << 7,
VIR_DOMAIN_DEF_PARSE_VALIDATE = 1 << 8,
+ /* don't validate os.type and arch against capabilities. Prevents
+ * VMs from disappearing when qemu is removed and libvirtd is restarted
+ */
+ VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS = 1 << 9,
} virDomainDefParseFlags;
typedef enum {
diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
index df19449..e725a23 100644
--- a/src/conf/snapshot_conf.c
+++ b/src/conf/snapshot_conf.c
@@ -270,6 +270,9 @@ virDomainSnapshotDefParse(xmlXPathContextPtr ctxt,
* clients will have to decide between best effort
* initialization or outright failure. */
if ((tmp = virXPathString("string(./domain/@type)", ctxt))) {
+ int domainflags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
+ if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL)
+ domainflags |= VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS;
xmlNodePtr domainNode = virXPathNode("./domain", ctxt);
VIR_FREE(tmp);
@@ -280,8 +283,7 @@ virDomainSnapshotDefParse(xmlXPathContextPtr ctxt,
}
def->dom = virDomainDefParseNode(ctxt->node->doc, domainNode,
caps, xmlopt,
- expectedVirtTypes,
- VIR_DOMAIN_DEF_PARSE_INACTIVE);
+ expectedVirtTypes, domainflags);
if (!def->dom)
goto cleanup;
} else {
--
2.3.5