src/qemu/qemu_migration.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
From: Jim Fehlig <jfehlig@suse.com>
When migrating with VIR_MIGRATE_UNDEFINE_SOURCE, qemuMigrationSrcConfirm()
and qemuMigrationSrcPerformJob() delete the domain's persistent config on
the source host but never emit a VIR_DOMAIN_EVENT_UNDEFINED lifecycle
event. Applications relying solely on domain events never learn the domain
was undefined on the source. Emit the event, reusing the existing
VIR_DOMAIN_EVENT_UNDEFINED_REMOVED detail since the semantics match
virDomainUndefine().
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
---
src/qemu/qemu_migration.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 797f83ca0d..f336437734 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -4279,6 +4279,7 @@ qemuMigrationSrcConfirm(virQEMUDriver *driver,
{
qemuMigrationJobPhase phase;
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+ virObjectEvent *event = NULL;
int ret = -1;
VIR_DEBUG("vm=%p, flags=0x%x, cancelled=%d", vm, flags, cancelled);
@@ -4325,11 +4326,15 @@ qemuMigrationSrcConfirm(virQEMUDriver *driver,
if (!cancelled && ret == 0 && flags & VIR_MIGRATE_UNDEFINE_SOURCE) {
virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
vm->persistent = 0;
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_UNDEFINED,
+ VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
}
qemuDomainRemoveInactive(vm, VIR_DOMAIN_UNDEFINE_TPM, true);
}
cleanup:
+ virObjectEventStateQueue(driver->domainEventState, event);
virDomainObjEndAPI(&vm);
return ret;
}
@@ -6328,6 +6333,7 @@ qemuMigrationSrcPerformJob(virQEMUDriver *driver,
bool v3proto)
{
virObjectEvent *event = NULL;
+ virObjectEvent *undefine_event = NULL;
int ret = -1;
virErrorPtr orig_err = NULL;
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
@@ -6419,6 +6425,9 @@ qemuMigrationSrcPerformJob(virQEMUDriver *driver,
if (flags & VIR_MIGRATE_UNDEFINE_SOURCE) {
virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
vm->persistent = 0;
+ undefine_event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_UNDEFINED,
+ VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
}
qemuDomainRemoveInactive(vm, 0, true);
}
@@ -6427,6 +6436,7 @@ qemuMigrationSrcPerformJob(virQEMUDriver *driver,
cleanup:
virObjectEventStateQueue(driver->domainEventState, event);
+ virObjectEventStateQueue(driver->domainEventState, undefine_event);
return ret;
}
--
2.51.0
On 10/13/26 22:47, Jim Fehlig via Devel wrote: > From: Jim Fehlig <jfehlig@suse.com> > > When migrating with VIR_MIGRATE_UNDEFINE_SOURCE, qemuMigrationSrcConfirm() > and qemuMigrationSrcPerformJob() delete the domain's persistent config on > the source host but never emit a VIR_DOMAIN_EVENT_UNDEFINED lifecycle > event. Applications relying solely on domain events never learn the domain > was undefined on the source. Emit the event, reusing the existing > VIR_DOMAIN_EVENT_UNDEFINED_REMOVED detail since the semantics match > virDomainUndefine(). > > Signed-off-by: Jim Fehlig <jfehlig@suse.com> > --- > src/qemu/qemu_migration.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
Thanks for the review Michal! Before pushing, I'd like to get opinions on an idea Claudio and I discussed off-list: a new VIR_DOMAIN_EVENT_UNDEFINED_MIGRATED detail for the UNDEFINED event. On 10/14/26 7:26 AM, Michal Prívozník wrote: > On 10/13/26 22:47, Jim Fehlig via Devel wrote: >> From: Jim Fehlig <jfehlig@suse.com> >> >> When migrating with VIR_MIGRATE_UNDEFINE_SOURCE, qemuMigrationSrcConfirm() >> and qemuMigrationSrcPerformJob() delete the domain's persistent config on >> the source host but never emit a VIR_DOMAIN_EVENT_UNDEFINED lifecycle >> event. Applications relying solely on domain events never learn the domain >> was undefined on the source. Emit the event, reusing the existing >> VIR_DOMAIN_EVENT_UNDEFINED_REMOVED detail since the semantics match >> virDomainUndefine(). While the semantics are the same within libvirt (virDomainDeleteConfig; vm->persistent=0;), the distinction between UNDEFINED_REMOVED and UNDEFINED_MIGRATED could be important to a platform using libvirt events for state synchronization. If agreed, I'll respin a V2 adding the new detail. Regards, Jim >> >> Signed-off-by: Jim Fehlig <jfehlig@suse.com> >> --- >> src/qemu/qemu_migration.c | 10 ++++++++++ >> 1 file changed, 10 insertions(+) > > Reviewed-by: Michal Privoznik <mprivozn@redhat.com> > > Michal >
On Wed, Oct 14, 2026 at 10:41:46AM -0600, Jim Fehlig via Devel wrote:
> Thanks for the review Michal! Before pushing, I'd like to get opinions on an
> idea Claudio and I discussed off-list: a new
> VIR_DOMAIN_EVENT_UNDEFINED_MIGRATED detail for the UNDEFINED event.
>
> On 10/14/26 7:26 AM, Michal Prívozník wrote:
> > On 10/13/26 22:47, Jim Fehlig via Devel wrote:
> > > From: Jim Fehlig <jfehlig@suse.com>
> > >
> > > When migrating with VIR_MIGRATE_UNDEFINE_SOURCE, qemuMigrationSrcConfirm()
> > > and qemuMigrationSrcPerformJob() delete the domain's persistent config on
> > > the source host but never emit a VIR_DOMAIN_EVENT_UNDEFINED lifecycle
> > > event. Applications relying solely on domain events never learn the domain
> > > was undefined on the source. Emit the event, reusing the existing
> > > VIR_DOMAIN_EVENT_UNDEFINED_REMOVED detail since the semantics match
> > > virDomainUndefine().
>
> While the semantics are the same within libvirt (virDomainDeleteConfig;
> vm->persistent=0;), the distinction between UNDEFINED_REMOVED and
> UNDEFINED_MIGRATED could be important to a platform using libvirt events for
> state synchronization. If agreed, I'll respin a V2 adding the new detail.
Yes, I think it deserves a new constant.
The "reason" should always reflect the API call or operation that
/caused/ the lifecycle change to take place.
IMHO "UNDEFINED_REMOVED" corresponds to the explicit virDomainUndefine
API call/operation.
We use "MIGRATED" as a reason for most other lifecycle events:
$ grep _MIGRATED include/libvirt/libvirt-domain.h
VIR_DOMAIN_RUNNING_MIGRATED = 2, /* migrated from another host (Since: 0.9.2) */
VIR_DOMAIN_SHUTOFF_MIGRATED = 4, /* migrated to another host (Since: 0.9.2) */
VIR_DOMAIN_EVENT_STARTED_MIGRATED = 1, /* Incoming migration from another host (Since: 0.5.0) */
VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1, /* Suspended for offline migration (Since: 0.5.0) */
VIR_DOMAIN_EVENT_RESUMED_MIGRATED = 1, /* Resumed for completion of migration (Since: 0.5.0) */
VIR_DOMAIN_EVENT_STOPPED_MIGRATED = 3, /* Migrated off to another host (Since: 0.5.0) */
and both EVENT_DEFINED and EVENT_UNDEFINED could justify doing
the same.
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
On 10/15/26 2:57 AM, Daniel P. Berrangé wrote: > On Wed, Oct 14, 2026 at 10:41:46AM -0600, Jim Fehlig via Devel wrote: >> Thanks for the review Michal! Before pushing, I'd like to get opinions on an >> idea Claudio and I discussed off-list: a new >> VIR_DOMAIN_EVENT_UNDEFINED_MIGRATED detail for the UNDEFINED event. >> >> On 10/14/26 7:26 AM, Michal Prívozník wrote: >>> On 10/13/26 22:47, Jim Fehlig via Devel wrote: >>>> From: Jim Fehlig <jfehlig@suse.com> >>>> >>>> When migrating with VIR_MIGRATE_UNDEFINE_SOURCE, qemuMigrationSrcConfirm() >>>> and qemuMigrationSrcPerformJob() delete the domain's persistent config on >>>> the source host but never emit a VIR_DOMAIN_EVENT_UNDEFINED lifecycle >>>> event. Applications relying solely on domain events never learn the domain >>>> was undefined on the source. Emit the event, reusing the existing >>>> VIR_DOMAIN_EVENT_UNDEFINED_REMOVED detail since the semantics match >>>> virDomainUndefine(). >> >> While the semantics are the same within libvirt (virDomainDeleteConfig; >> vm->persistent=0;), the distinction between UNDEFINED_REMOVED and >> UNDEFINED_MIGRATED could be important to a platform using libvirt events for >> state synchronization. If agreed, I'll respin a V2 adding the new detail. > > Yes, I think it deserves a new constant. > > The "reason" should always reflect the API call or operation that > /caused/ the lifecycle change to take place. > > IMHO "UNDEFINED_REMOVED" corresponds to the explicit virDomainUndefine > API call/operation. I've sent a V2 that adds UNDEFINED_MIGRATED https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/PKRALGECT2BUVBQYXV3QNVJMSGXO7R3F/ > > We use "MIGRATED" as a reason for most other lifecycle events: > > $ grep _MIGRATED include/libvirt/libvirt-domain.h > VIR_DOMAIN_RUNNING_MIGRATED = 2, /* migrated from another host (Since: 0.9.2) */ > VIR_DOMAIN_SHUTOFF_MIGRATED = 4, /* migrated to another host (Since: 0.9.2) */ > VIR_DOMAIN_EVENT_STARTED_MIGRATED = 1, /* Incoming migration from another host (Since: 0.5.0) */ > VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1, /* Suspended for offline migration (Since: 0.5.0) */ > VIR_DOMAIN_EVENT_RESUMED_MIGRATED = 1, /* Resumed for completion of migration (Since: 0.5.0) */ > VIR_DOMAIN_EVENT_STOPPED_MIGRATED = 3, /* Migrated off to another host (Since: 0.5.0) */ > > and both EVENT_DEFINED and EVENT_UNDEFINED could justify doing > the same. WRT the VIR_MIGRATE_PERSIST_DEST flag, the qemu driver already emits a DEFINED event with either VIR_DOMAIN_EVENT_DEFINED_ADDED or VIR_DOMAIN_EVENT_DEFINED_UPDATED detail. See qemuMigrationDstPersist() in qemu_migration.c https://gitlab.com/libvirt/libvirt/-/blob/master/src/qemu/qemu_migration.c?ref_type=heads#L6659 Same for the libxl driver. I think we'd risk app breakage if unconditionally changing that to VIR_DOMAIN_EVENT_DEFINED_MIGRATED, right? Regards, Jim
© 2016 - 2026 Red Hat, Inc.