conf: move virt type / os type / arch validation to post-parse

The XML parser currently calls virCapabilitiesDomainDataLookup during
parsing to find the domain capabilities matching the triple

  (virt type, os type, arch)

This is, however, bogus with the QEMU driver as it assumes that there
is an emulator known to the default driver capabilities that matches
this triple. It is entirely possible for the driver to be parsing an
XML file with a custom emulator path specified pointing to a binary
that doesn't exist in the default driver capabilities.  This will,
for example be the case on a RHEL host which only installs the host
native emulator to /usr/bin. The user can have built a custom QEMU
for non-native arches into $HOME and wish to use that.

Aside from validation, this call is also used to fill in a machine type
for the guest if not otherwise specified. Again, this data may be
incorrect for the QEMU driver because it is not taking account of
the emulator binary that is referenced.

To start fixing this, move the validation to the post-parse callbacks
where more intelligent driver specific logic can be applied.

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2019-11-26 16:09:33 +00:00
parent 6430c00552
commit 2578d74aee
13 changed files with 92 additions and 31 deletions

View File

@ -74,11 +74,16 @@ bhyveDomainDefNeedsISAController(virDomainDefPtr def)
static int
bhyveDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps G_GNUC_UNUSED,
virCapsPtr caps,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_UNUSED)
{
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
/* Add an implicit PCI root controller */
if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0)

View File

@ -816,6 +816,23 @@ virCapabilitiesDomainDataLookup(virCapsPtr caps,
}
bool
virCapabilitiesDomainSupported(virCapsPtr caps,
int ostype,
virArch arch,
int virttype)
{
g_autofree virCapsDomainDataPtr capsdata = NULL;
capsdata = virCapabilitiesDomainDataLookup(caps, ostype,
arch,
virttype,
NULL, NULL);
return capsdata != NULL;
}
int
virCapabilitiesAddStoragePool(virCapsPtr caps,
int poolType)

View File

@ -309,6 +309,13 @@ virCapabilitiesDomainDataLookup(virCapsPtr caps,
const char *emulator,
const char *machinetype);
bool
virCapabilitiesDomainSupported(virCapsPtr caps,
int ostype,
virArch arch,
int domaintype);
void
virCapabilitiesClearHostNUMACellCPUTopology(virCapsHostNUMACellCPUPtr cpu,
size_t ncpus);

View File

@ -19613,14 +19613,11 @@ virDomainCachetuneDefParse(virDomainDefPtr def,
static int
virDomainDefParseCaps(virDomainDefPtr def,
xmlXPathContextPtr ctxt,
virDomainXMLOptionPtr xmlopt,
virCapsPtr caps,
unsigned int flags)
virDomainXMLOptionPtr xmlopt)
{
g_autofree char *virttype = NULL;
g_autofree char *arch = NULL;
g_autofree char *ostype = NULL;
g_autofree virCapsDomainDataPtr capsdata = NULL;
virttype = virXPathString("string(./@type)", ctxt);
ostype = virXPathString("string(./os/type[1])", ctxt);
@ -19681,18 +19678,6 @@ virDomainDefParseCaps(virDomainDefPtr def,
def->os.arch = virArchFromHost();
}
if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
def->os.arch,
def->virtType,
NULL, NULL))) {
if (!(flags & VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE))
return -1;
virResetLastError();
} else {
if (!def->os.machine)
def->os.machine = g_strdup(capsdata->machinetype);
}
return 0;
}
@ -19846,7 +19831,7 @@ virDomainDefParseXML(xmlDocPtr xml,
id = -1;
def->id = (int)id;
if (virDomainDefParseCaps(def, ctxt, xmlopt, caps, flags) < 0)
if (virDomainDefParseCaps(def, ctxt, xmlopt) < 0)
goto error;
/* Extract domain name */

View File

@ -54,6 +54,7 @@ virCapabilitiesAddStoragePool;
virCapabilitiesAllocMachines;
virCapabilitiesClearHostNUMACellCPUTopology;
virCapabilitiesDomainDataLookup;
virCapabilitiesDomainSupported;
virCapabilitiesFormatXML;
virCapabilitiesFreeGuest;
virCapabilitiesFreeMachines;

View File

@ -367,11 +367,16 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
static int
libxlDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps G_GNUC_UNUSED,
virCapsPtr caps,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_UNUSED)
{
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
/* Xen PV domains always have a PV console, so add one to the domain config
* via post-parse callback if not explicitly specified in the XML. */
if (def->os.type != VIR_DOMAIN_OSTYPE_HVM && def->nconsoles == 0) {

View File

@ -356,6 +356,11 @@ virLXCDomainDefPostParse(virDomainDefPtr def,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_UNUSED)
{
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
/* check for emulator and create a default one if needed */
if (!def->emulator &&
!(def->emulator = virDomainDefGetDefaultEmulator(def, caps)))

View File

@ -1082,11 +1082,16 @@ int openvzGetVEID(const char *name)
static int
openvzDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps G_GNUC_UNUSED,
virCapsPtr caps,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_UNUSED)
{
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
/* fill the init path */
if (def->os.type == VIR_DOMAIN_OSTYPE_EXE && !def->os.init)
def->os.init = g_strdup("/sbin/init");

View File

@ -1061,12 +1061,17 @@ openSSHSession(virConnectPtr conn, virConnectAuthPtr auth,
static int
phypDomainDefPostParse(virDomainDefPtr def G_GNUC_UNUSED,
virCapsPtr caps G_GNUC_UNUSED,
phypDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_UNUSED)
{
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
return 0;
}

View File

@ -4691,7 +4691,7 @@ qemuDomainDefPostParseBasic(virDomainDefPtr def,
static int
qemuDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps G_GNUC_UNUSED,
virCapsPtr caps,
unsigned int parseFlags,
void *opaque,
void *parseOpaque)
@ -4703,6 +4703,11 @@ qemuDomainDefPostParse(virDomainDefPtr def,
* with the capabilities populated. */
virQEMUCapsPtr qemuCaps = parseOpaque;
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
if (def->os.bootloader || def->os.bootloaderArgs) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("bootloader is not supported by QEMU"));
@ -4710,9 +4715,15 @@ qemuDomainDefPostParse(virDomainDefPtr def,
}
if (!def->os.machine) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing machine type"));
return -1;
g_autofree virCapsDomainDataPtr capsdata = NULL;
if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
def->os.arch,
def->virtType,
NULL, NULL))) {
return -1;
}
def->os.machine = g_strdup(capsdata->machinetype);
}
qemuDomainNVRAMPathGenerate(cfg, def);

View File

@ -116,12 +116,17 @@ vmwareDataFreeFunc(void *data)
}
static int
vmwareDomainDefPostParse(virDomainDefPtr def G_GNUC_UNUSED,
virCapsPtr caps G_GNUC_UNUSED,
vmwareDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_UNUSED)
{
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
return 0;
}

View File

@ -529,12 +529,17 @@ VIR_ENUM_IMPL(virVMXControllerModelSCSI,
*/
static int
virVMXDomainDefPostParse(virDomainDefPtr def G_GNUC_UNUSED,
virCapsPtr caps G_GNUC_UNUSED,
virVMXDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_UNUSED)
{
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
return 0;
}

View File

@ -241,11 +241,16 @@ vzDomainDefAddDefaultInputDevices(virDomainDefPtr def)
static int
vzDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps G_GNUC_UNUSED,
virCapsPtr caps,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_UNUSED)
{
if (!virCapabilitiesDomainSupported(caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
if (vzDomainDefAddDefaultInputDevices(def) < 0)
return -1;