Use the new facility which allows to ignore failures in post parse callbacks if they are not fatal so that VM configs are not lost if the emulator binary is missing.
If qemuCaps can't be populated on daemon restart skip certain portions of the post parse callbacks during config reload and re-run the callback during VM startup. This fixes VMs vanishing if the emulator binary was broken or uninstalled and libvirtd was restarted. --- src/qemu/qemu_domain.c | 20 ++++++++++++++++++-- src/qemu/qemu_process.c | 9 +++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index e28b373a9..e2531cdcf 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2932,7 +2932,7 @@ qemuDomainDefPostParseBasic(virDomainDefPtr def, /* check for emulator and create a default one if needed */ if (!def->emulator && !(def->emulator = virDomainDefGetDefaultEmulator(def, caps))) - return -1; + return 1; return 0; } @@ -2947,6 +2947,9 @@ qemuDomainDefPostParse(virDomainDefPtr def, { virQEMUDriverPtr driver = opaque; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + /* Note that qemuCaps may be NULL when this function is called. This + * function shall not fail in that case. It will be re-run on VM startup + * with the capabilities populated. */ virQEMUCapsPtr qemuCaps = parseOpaque; int ret = -1; @@ -3575,6 +3578,9 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, void *parseOpaque) { virQEMUDriverPtr driver = opaque; + /* Note that qemuCaps may be NULL when this function is called. This + * function shall not fail in that case. It will be re-run on VM startup + * with the capabilities populated. */ virQEMUCapsPtr qemuCaps = parseOpaque; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); int ret = -1; @@ -3700,9 +3706,19 @@ qemuDomainDefAssignAddresses(virDomainDef *def, void *parseOpaque) { virQEMUDriverPtr driver = opaque; + /* Note that qemuCaps may be NULL when this function is called. This + * function shall not fail in that case. It will be re-run on VM startup + * with the capabilities populated. */ virQEMUCapsPtr qemuCaps = parseOpaque; bool newDomain = parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE; + /* Skip address assignment if @qemuCaps is not present. In such case devices + * which are automatically added may be missing. Additionally @qemuCaps should + * only be missing when reloading configs, thus addresses were already + * assigned. */ + if (!qemuCaps) + return 1; + return qemuDomainAssignAddresses(def, qemuCaps, driver, NULL, newDomain); } @@ -3718,7 +3734,7 @@ qemuDomainPostParseDataAlloc(const virDomainDef *def, if (!(*parseOpaque = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator))) - return -1; + return 1; return 0; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index fed2bc588..589d0ed2c 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4691,6 +4691,15 @@ qemuProcessInit(virQEMUDriverPtr driver, if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup; + /* in case when the post parse callback failed we need to re-run it on the + * old config prior we start the VM */ + if (vm->def->postParseFailed) { + VIR_DEBUG("re-running the post parse callback"); + + if (virDomainDefPostParse(vm->def, caps, 0, driver->xmlopt, NULL) < 0) + goto cleanup; + } + VIR_DEBUG("Determining emulator version"); virObjectUnref(priv->qemuCaps); if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache, -- 2.14.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list