From 0960b4c91901a4a01f8facba13885291d07037bc Mon Sep 17 00:00:00 2001 From: nvazquez Date: Tue, 23 Dec 2025 23:09:46 -0300 Subject: [PATCH 1/3] Fix: Condition for aborting migration, resume paused VMs on destination --- .../wrapper/LibvirtMigrateCommandWrapper.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java index 32f2a4b122ca..a263addfe3b3 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java @@ -246,7 +246,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0. while (!executor.isTerminated()) { Thread.sleep(100); sleeptime += 100; - if (sleeptime == 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state + if (sleeptime >= 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state final int migrateDowntime = libvirtComputingResource.getMigrateDowntime(); if (migrateDowntime > 0 ) { try { @@ -272,7 +272,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0. } catch (final LibvirtException e) { logger.info("Couldn't get VM domain state after " + sleeptime + "ms: " + e.getMessage()); } - if (state != null && state == DomainState.VIR_DOMAIN_RUNNING) { + if (state != null && (state == DomainState.VIR_DOMAIN_RUNNING || state == DomainState.VIR_DOMAIN_PAUSED)) { try { DomainJobInfo job = dm.getJobInfo(); logger.info(String.format("Aborting migration of VM [%s] with domain job [%s] due to time out after %d seconds.", vmName, job, migrateWait)); @@ -314,6 +314,21 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0. if (logger.isDebugEnabled()) { logger.debug(String.format("Cleaning the disks of VM [%s] in the source pool after VM migration finished.", vmName)); } + DomainState dmState = null; + try { + dmState = destDomain.getInfo().state; + } catch (final LibvirtException e) { + logger.info("Failed to get domain state for VM: " + vmName + " due to: " + e.getMessage()); + } + + if (dmState == DomainState.VIR_DOMAIN_PAUSED) { + logger.info("Resuming VM " + vmName + " on destination after migration"); + try { + destDomain.resume(); + } catch (final Exception e) { + logger.error("Failed to resume vm " + vmName + " on destination after migration due to : " + e.getMessage()); + } + } deleteOrDisconnectDisksOnSourcePool(libvirtComputingResource, migrateDiskInfoList, disks); libvirtComputingResource.cleanOldSecretsByDiskDef(conn, disks); } From b204e5b003732b2940835a47814ef9758d5c680a Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 15 Jan 2026 00:25:14 -0300 Subject: [PATCH 2/3] Refactor downtime logic --- .../wrapper/LibvirtMigrateCommandWrapper.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java index a263addfe3b3..572b047b06a3 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java @@ -243,20 +243,21 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0. final Future migrateThread = executor.submit(worker); executor.shutdown(); long sleeptime = 0; + final int migrateDowntime = libvirtComputingResource.getMigrateDowntime(); + boolean isMigrateDowntimeSet = false; + while (!executor.isTerminated()) { Thread.sleep(100); sleeptime += 100; - if (sleeptime >= 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state - final int migrateDowntime = libvirtComputingResource.getMigrateDowntime(); - if (migrateDowntime > 0 ) { - try { - final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime); - if (setDowntime == 0 ) { - logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms"); - } - } catch (final LibvirtException e) { - logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage()); + if (!isMigrateDowntimeSet && migrateDowntime > 0 && sleeptime >= 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state + try { + final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime); + if (setDowntime == 0 ) { + isMigrateDowntimeSet = true; + logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms"); } + } catch (final LibvirtException e) { + logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage()); } } if (sleeptime % 1000 == 0) { From 3f1cf043c82baba3081a30f6ef80ee9fe7902141 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 15 Jan 2026 01:14:02 -0300 Subject: [PATCH 3/3] Refactor into new method --- .../wrapper/LibvirtMigrateCommandWrapper.java | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java index 572b047b06a3..f9d86e05329f 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java @@ -315,21 +315,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0. if (logger.isDebugEnabled()) { logger.debug(String.format("Cleaning the disks of VM [%s] in the source pool after VM migration finished.", vmName)); } - DomainState dmState = null; - try { - dmState = destDomain.getInfo().state; - } catch (final LibvirtException e) { - logger.info("Failed to get domain state for VM: " + vmName + " due to: " + e.getMessage()); - } - - if (dmState == DomainState.VIR_DOMAIN_PAUSED) { - logger.info("Resuming VM " + vmName + " on destination after migration"); - try { - destDomain.resume(); - } catch (final Exception e) { - logger.error("Failed to resume vm " + vmName + " on destination after migration due to : " + e.getMessage()); - } - } + resumeDomainIfPaused(destDomain, vmName); deleteOrDisconnectDisksOnSourcePool(libvirtComputingResource, migrateDiskInfoList, disks); libvirtComputingResource.cleanOldSecretsByDiskDef(conn, disks); } @@ -394,6 +380,28 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0. return new MigrateAnswer(command, result == null, result, null); } + private DomainState getDestDomainState(Domain destDomain, String vmName) { + DomainState dmState = null; + try { + dmState = destDomain.getInfo().state; + } catch (final LibvirtException e) { + logger.info("Failed to get domain state for VM: " + vmName + " due to: " + e.getMessage()); + } + return dmState; + } + + private void resumeDomainIfPaused(Domain destDomain, String vmName) { + DomainState dmState = getDestDomainState(destDomain, vmName); + if (dmState == DomainState.VIR_DOMAIN_PAUSED) { + logger.info("Resuming VM " + vmName + " on destination after migration"); + try { + destDomain.resume(); + } catch (final Exception e) { + logger.error("Failed to resume vm " + vmName + " on destination after migration due to : " + e.getMessage()); + } + } + } + /** * Gets the disk labels (vda, vdb...) of the disks mapped for migration on mapMigrateStorage. * @param diskDefinitions list of all the disksDefinitions of the VM.