From f84a50722428dce41e52cbe9ff7e5c523154c0ac Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Mon, 30 Mar 2026 15:15:37 -0400 Subject: [PATCH] restrict pre and post migration commands to only kvm hosts where vm has CLVM/CLVM-NG volumes --- .../cloud/vm/VirtualMachineManagerImpl.java | 88 ++++++++++--------- .../StorageSystemDataMotionStrategy.java | 5 +- 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 8a773f74ab2..cb1adaf38b5 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3116,21 +3116,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac final VirtualMachineTO to = toVmTO(profile); - logger.info("Sending PreMigrationCommand to source host {} for VM {}", srcHostId, vm.getInstanceName()); - final PreMigrationCommand preMigCmd = new PreMigrationCommand(to, vm.getInstanceName()); - Answer preMigAnswer = null; - try { - preMigAnswer = _agentMgr.send(srcHostId, preMigCmd); - if (preMigAnswer == null || !preMigAnswer.getResult()) { - final String details = preMigAnswer != null ? preMigAnswer.getDetails() : "null answer returned"; - final String msg = "Failed to prepare source host for migration: " + details; - logger.error("Failed to prepare source host {} for migration of VM {}: {}", srcHostId, vm.getInstanceName(), details); - throw new CloudRuntimeException(msg); - } - logger.info("Successfully prepared source host {} for migration of VM {}", srcHostId, vm.getInstanceName()); - } catch (final AgentUnavailableException | OperationTimedoutException e) { - logger.error("Failed to send PreMigrationCommand to source host {}: {}", srcHostId, e.getMessage(), e); - throw new CloudRuntimeException("Failed to prepare source host for migration: " + e.getMessage(), e); + if (vm.getHypervisorType() == HypervisorType.KVM && hasClvmVolumes(vm.getId())) { + executePreMigrationCommand(to, vm.getInstanceName(), srcHostId); } final PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to); @@ -3264,21 +3251,23 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac logger.warn("Error while checking the vm {} on host {}", vm, dest.getHost(), e); } migrated = true; - try { - logger.info("Executing post-migration tasks for VM {} on destination host {}", vm.getInstanceName(), dstHostId); - final PostMigrationCommand postMigrationCommand = new PostMigrationCommand(to, vm.getInstanceName()); - final Answer postMigrationAnswer = _agentMgr.send(dstHostId, postMigrationCommand); + if (vm.getHypervisorType() == HypervisorType.KVM && hasClvmVolumes(vm.getId())) { + try { + logger.info("Executing post-migration tasks for VM {} with CLVM volumes on destination host {}", vm.getInstanceName(), dstHostId); + final PostMigrationCommand postMigrationCommand = new PostMigrationCommand(to, vm.getInstanceName()); + final Answer postMigrationAnswer = _agentMgr.send(dstHostId, postMigrationCommand); - if (postMigrationAnswer == null || !postMigrationAnswer.getResult()) { - final String details = postMigrationAnswer != null ? postMigrationAnswer.getDetails() : "null answer returned"; - logger.warn("Post-migration tasks failed for VM {} on destination host {}: {}. Migration completed but some cleanup may be needed.", - vm.getInstanceName(), dstHostId, details); - } else { - logger.info("Successfully completed post-migration tasks for VM {} on destination host {}", vm.getInstanceName(), dstHostId); + if (postMigrationAnswer == null || !postMigrationAnswer.getResult()) { + final String details = postMigrationAnswer != null ? postMigrationAnswer.getDetails() : "null answer returned"; + logger.warn("Post-migration tasks failed for VM {} on destination host {}: {}. Migration completed but some cleanup may be needed.", + vm.getInstanceName(), dstHostId, details); + } else { + logger.info("Successfully completed post-migration tasks for VM {} on destination host {}", vm.getInstanceName(), dstHostId); + } + } catch (Exception e) { + logger.warn("Exception during post-migration tasks for VM {} on destination host {}: {}. Migration completed but some cleanup may be needed.", + vm.getInstanceName(), dstHostId, e.getMessage(), e); } - } catch (Exception e) { - logger.warn("Exception during post-migration tasks for VM {} on destination host {}: {}. Migration completed but some cleanup may be needed.", - vm.getInstanceName(), dstHostId, e.getMessage(), e); } updateClvmLockHostForVmVolumes(vm.getId(), dstHostId); @@ -4965,21 +4954,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac // Step 1: Send PreMigrationCommand to source host to convert CLVM volumes to shared mode // This must happen BEFORE PrepareForMigrationCommand on destination to avoid lock conflicts - logger.info("Sending PreMigrationCommand to source host {} for VM {}", srcHostId, vm.getInstanceName()); - final PreMigrationCommand preMigCmd = new PreMigrationCommand(to, vm.getInstanceName()); - Answer preMigAnswer = null; - try { - preMigAnswer = _agentMgr.send(srcHostId, preMigCmd); - if (preMigAnswer == null || !preMigAnswer.getResult()) { - final String details = preMigAnswer != null ? preMigAnswer.getDetails() : "null answer returned"; - final String msg = "Failed to prepare source host for migration: " + details; - logger.error("Failed to prepare source host {} for migration of VM {}: {}", srcHostId, vm.getInstanceName(), details); - throw new CloudRuntimeException(msg); - } - logger.info("Successfully prepared source host {} for migration of VM {}", srcHostId, vm.getInstanceName()); - } catch (final AgentUnavailableException | OperationTimedoutException e) { - logger.error("Failed to send PreMigrationCommand to source host {}: {}", srcHostId, e.getMessage(), e); - throw new CloudRuntimeException("Failed to prepare source host for migration: " + e.getMessage(), e); + if (vm.getHypervisorType() == HypervisorType.KVM && hasClvmVolumes(vm.getId())) { + executePreMigrationCommand(to, vm.getInstanceName(), srcHostId); } // Step 2: Send PrepareForMigrationCommand to destination host @@ -6406,6 +6382,32 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return findClusterAndHostIdForVm(vm, false); } + private boolean hasClvmVolumes(long vmId) { + List volumes = _volsDao.findByInstance(vmId); + return volumes.stream() + .map(v -> _storagePoolDao.findById(v.getPoolId())) + .anyMatch(pool -> pool != null && ClvmLockManager.isClvmPoolType(pool.getPoolType())); + } + + private void executePreMigrationCommand(VirtualMachineTO to, String vmInstanceName, long srcHostId) { + logger.info("Sending PreMigrationCommand to source host {} for VM {} with CLVM volumes", srcHostId, vmInstanceName); + final PreMigrationCommand preMigCmd = new PreMigrationCommand(to, vmInstanceName); + Answer preMigAnswer = null; + try { + preMigAnswer = _agentMgr.send(srcHostId, preMigCmd); + if (preMigAnswer == null || !preMigAnswer.getResult()) { + final String details = preMigAnswer != null ? preMigAnswer.getDetails() : "null answer returned"; + final String msg = "Failed to prepare source host for migration: " + details; + logger.error("Failed to prepare source host {} for migration of VM {}: {}", srcHostId, vmInstanceName, details); + throw new CloudRuntimeException(msg); + } + logger.info("Successfully prepared source host {} for migration of VM {}", srcHostId, vmInstanceName); + } catch (final AgentUnavailableException | OperationTimedoutException e) { + logger.error("Failed to send PreMigrationCommand to source host {}: {}", srcHostId, e.getMessage(), e); + throw new CloudRuntimeException("Failed to prepare source host for migration: " + e.getMessage(), e); + } + } + @Override public Pair findClusterAndHostIdForVm(long vmId) { VMInstanceVO vm = _vmDao.findById(vmId); diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java index 49bd3e8e031..cba7dbfbea4 100644 --- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java +++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java @@ -2233,8 +2233,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy { boolean hasClvmSource = volumeDataStoreMap.keySet().stream() .map(v -> _storagePoolDao.findById(v.getPoolId())) .anyMatch(p -> p != null && (p.getPoolType() == StoragePoolType.CLVM || p.getPoolType() == StoragePoolType.CLVM_NG)); - - if (hasClvmSource) { + if (hasClvmSource && srcHost.getHypervisorType() == HypervisorType.KVM) { logger.info("CLVM/CLVM_NG source pool detected for VM [{}], sending PreMigrationCommand to source host [{}] to convert volumes to shared mode.", vmTO.getName(), srcHost.getId()); PreMigrationCommand preMigCmd = new PreMigrationCommand(vmTO, vmTO.getName()); try { @@ -2248,6 +2247,8 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy { } catch (Exception e) { logger.warn("Failed to send PreMigrationCommand to source host [{}] for VM [{}]: {}. Migration will continue but may fail if volumes are exclusively locked.", srcHost.getId(), vmTO.getName(), e.getMessage()); } + } else if (hasClvmSource) { + logger.debug("Skipping PreMigrationCommand for non-KVM hypervisor type: {} on host [{}]", srcHost.getHypervisorType(), srcHost.getId()); } }