From 388fdc2b3ee1e3c02f5e0bebdfe8167d3de788e6 Mon Sep 17 00:00:00 2001 From: Henrique Sato Date: Tue, 17 Mar 2026 19:39:04 -0300 Subject: [PATCH] [VMware] Apply IOPS in resize/migrate --- .../api/storage/MigrateVolumeCommand.java | 18 ++++++ .../api/storage/ResizeVolumeCommand.java | 19 +++++- .../service/VolumeOrchestrationService.java | 2 +- .../orchestration/VolumeOrchestrator.java | 9 +-- .../motion/AncientDataMotionStrategy.java | 1 + .../vmware/resource/VmwareResource.java | 62 ++++++++++++++++++- .../motion/VmwareStorageMotionStrategy.java | 21 +++++++ .../CloudStackPrimaryDataStoreDriverImpl.java | 2 + .../cloud/storage/VolumeApiServiceImpl.java | 37 ++++++++--- .../vm/UnmanagedVMsManagerImpl.java | 2 +- .../vmware/mo/VirtualMachineMO.java | 6 +- 11 files changed, 159 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java b/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java index 70375c30a1bb..2d0f94e6a6c0 100644 --- a/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java +++ b/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java @@ -36,6 +36,8 @@ public class MigrateVolumeCommand extends Command { String attachedVmName; Volume.Type volumeType; String hostGuidInTargetCluster; + Long newMaxIops; + Long newMinIops; private DataTO srcData; private DataTO destData; @@ -150,4 +152,20 @@ public int getWaitInMillSeconds() { public boolean isReconcile() { return true; } + + public Long getNewMinIops() { + return newMinIops; + } + + public void setNewMinIops(Long newMinIops) { + this.newMinIops = newMinIops; + } + + public Long getNewMaxIops() { + return newMaxIops; + } + + public void setNewMaxIops(Long newMaxIops) { + this.newMaxIops = newMaxIops; + } } diff --git a/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java b/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java index db867698e91e..a8d88ca3124d 100644 --- a/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java +++ b/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java @@ -33,6 +33,8 @@ public class ResizeVolumeCommand extends Command { private boolean shrinkOk; private String vmInstance; private String chainInfo; + private Long newMaxIops; + private Long newMinIops; /* For managed storage */ private boolean managed; @@ -70,7 +72,6 @@ public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, L public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, boolean isManaged, String iScsiName) { this(path, pool, currentSize, newSize, shrinkOk, vmInstance); - this.iScsiName = iScsiName; this.managed = isManaged; } @@ -120,4 +121,20 @@ public void clearPassphrase() { public boolean executeInSequence() { return false; } + + public Long getNewMaxIops() { + return newMaxIops; + } + + public void setNewMaxIops(Long newMaxIops) { + this.newMaxIops = newMaxIops; + } + + public Long getNewMinIops() { + return newMinIops; + } + + public void setNewMinIops(Long newMinIops) { + this.newMinIops = newMinIops; + } } diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java index 168822c21ebc..c461b204c9d7 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java @@ -111,7 +111,7 @@ VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, UserVm vm) throws StorageUnavailableException; - Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException; + Volume migrateVolume(Volume volume, StoragePool destPool, DiskOffering newDiskOffering) throws StorageUnavailableException; Volume liveMigrateVolume(Volume volume, StoragePool destPool); diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index af8ff83396db..ff2aa8f72745 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -329,7 +329,7 @@ public VolumeInfo moveVolume(VolumeInfo volumeInfo, long destPoolDcId, Long dest throw new CloudRuntimeException(String.format("Failed to find a storage pool with enough capacity to move the volume [%s] to.", volumeToString)); } - Volume newVol = migrateVolume(volumeInfo, destPool); + Volume newVol = migrateVolume(volumeInfo, destPool, diskOffering); return volFactory.getVolume(newVol.getId()); } @@ -1419,13 +1419,14 @@ private void checkConcurrentJobsPerDatastoreThreshhold(final StoragePool destPoo @Override @DB - public Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException { + public Volume migrateVolume(Volume volume, StoragePool destPool, DiskOffering newDiskOffering) throws StorageUnavailableException { String volumeToString = getVolumeIdentificationInfos(volume); VolumeInfo vol = volFactory.getVolume(volume.getId()); if (vol == null) { throw new CloudRuntimeException(String.format("Volume migration failed because volume [%s] is null.", volumeToString)); } + vol.addPayload(newDiskOffering); if (destPool == null) { throw new CloudRuntimeException("Volume migration failed because the destination storage pool is not available."); } @@ -1554,7 +1555,7 @@ public boolean storageMigration(VirtualMachineProfile vm, Map entry : volumeStoragePoolMap.entrySet()) { - Volume result = migrateVolume(entry.getKey(), entry.getValue()); + Volume result = migrateVolume(entry.getKey(), entry.getValue(), null); if (result == null) { return false; } @@ -2019,7 +2020,7 @@ public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws Sto } else if (task.type == VolumeTaskType.MIGRATE) { store = (PrimaryDataStore) dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary); updateVolumeSize(store, task.volume); - vol = migrateVolume(task.volume, store); + vol = migrateVolume(task.volume, store, null); } else if (task.type == VolumeTaskType.RECREATE) { Pair result = recreateVolume(task.volume, vm, dest); store = (PrimaryDataStore) dataStoreMgr.getDataStore(result.second().getId(), DataStoreRole.Primary); diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 8145158dfa40..e668c5ac2c4d 100644 --- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -546,6 +546,7 @@ protected Answer migrateVolumeToPool(DataObject srcData, DataObject destData) { StoragePool srcPool = (StoragePool)dataStoreMgr.getDataStore(srcData.getDataStore().getId(), DataStoreRole.Primary); StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(destData.getDataStore().getId(), DataStoreRole.Primary); MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool, volume.getAttachedVmName(), volume.getVolumeType(), waitInterval, volume.getChainInfo()); + if (srcPool.getParent() != 0) { command.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 831e222200ab..ff0fe10fbb40 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -45,6 +45,7 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.vmware.vim25.StorageIOAllocationInfo; import com.cloud.agent.api.CleanupVMCommand; import javax.naming.ConfigurationException; import javax.xml.datatype.XMLGregorianCalendar; @@ -78,6 +79,7 @@ import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.logging.log4j.ThreadContext; +import org.apache.commons.lang3.ObjectUtils; import org.joda.time.Duration; import com.cloud.agent.IAgentControl; @@ -874,6 +876,8 @@ private Answer execute(ResizeVolumeCommand cmd) { boolean managed = cmd.isManaged(); String poolUUID = cmd.getPoolUuid(); String chainInfo = cmd.getChainInfo(); + Long newMinIops = cmd.getNewMinIops(); + Long newMaxIops = cmd.getNewMaxIops(); boolean useWorkerVm = false; VmwareContext context = getServiceContext(); @@ -888,8 +892,6 @@ private Answer execute(ResizeVolumeCommand cmd) { oldSize / (float) ResourceType.bytesToMiB, newSize / (float) ResourceType.bytesToMiB, vmName); logger.error(errorMsg); throw new Exception(errorMsg); - } else if (newSize == oldSize) { - return new ResizeVolumeAnswer(cmd, true, "success", newSize * ResourceType.bytesToKiB); } if (vmName.equalsIgnoreCase("none")) { @@ -983,6 +985,8 @@ private Answer execute(ResizeVolumeCommand cmd) { VirtualDisk disk = getDiskAfterResizeDiskValidations(vmMo, path); String vmdkAbsFile = VmwareHelper.getAbsoluteVmdkFile(disk); + setDiskIops(disk, newMinIops, newMaxIops); + if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) { vmMo.updateAdapterTypeIfRequired(vmdkAbsFile); } @@ -1034,6 +1038,22 @@ private Answer execute(ResizeVolumeCommand cmd) { } } + /** + * Sets the disk IOPS which is the sum of min IOPS and max IOPS; if they are null, the IOPS limit is set to -1 (unlimited). + */ + private void setDiskIops(VirtualDisk disk, Long newMinIops, Long newMaxIops) { + StorageIOAllocationInfo storageIOAllocation = new StorageIOAllocationInfo(); + Long iops = -1L; + + if (ObjectUtils.allNotNull(newMinIops, newMaxIops) && newMinIops > 0 && newMaxIops > 0) { + iops = newMinIops + newMaxIops; + } + + storageIOAllocation.setLimit(iops); + logger.debug(LogUtils.logGsonWithoutException("Setting [%s] as the IOPS limit of disk [%s].", iops == -1L ? "unlimited" : iops, disk)); + disk.setStorageIOAllocation(storageIOAllocation); + } + private VirtualDisk getDiskAfterResizeDiskValidations(VirtualMachineMO vmMo, String volumePath) throws Exception { Pair vdisk = vmMo.getDiskDevice(volumePath); if (vdisk == null) { @@ -4426,7 +4446,7 @@ protected GetVolumeStatsAnswer execute(GetVolumeStatsCommand cmd) { for (String diskPath : disks) { DatastoreFile file = new DatastoreFile(diskPath); VirtualMachineMO vmMo = dcMo.findVm(file.getDir()); - Pair vds = vmMo.getDiskDevice(file.getFileName(), true); + Pair vds = vmMo.getDiskDevice(file.getFileName(), true, false); long virtualsize = vds.first().getCapacityInKB() * 1024; long physicalsize = primaryStorageDatastoreMo.fileDiskSize(file.getPath()); if (statEntry.containsKey(chainInfo)) { @@ -5179,6 +5199,8 @@ private Answer execute(MigrateVolumeCommand cmd) { volumePath = vmMo.getVmdkFileBaseName(disk); } } + + setDiskIops(cmd, vmMo, volumePath); VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, targetDsMo.getName())); MigrateVolumeAnswer answer = new MigrateVolumeAnswer(cmd, true, null, volumePath); @@ -5191,6 +5213,40 @@ private Answer execute(MigrateVolumeCommand cmd) { } } + /** + * Sets the disk IOPS limitation, if the {@link MigrateVolumeCommand} did not specify this limitation, then it is set to -1 (unlimited). + */ + private void setDiskIops(MigrateVolumeCommand cmd, VirtualMachineMO vmMo, String volumePath) throws Exception { + Long newIops = -1L; + Long newMinIops = cmd.getNewMinIops(); + Long newMaxIops = cmd.getNewMaxIops(); + + if (ObjectUtils.allNotNull(newMinIops, newMaxIops) && newMinIops > 0 && newMaxIops > 0) { + newIops = newMinIops + newMaxIops; + } + + VirtualDisk disk = vmMo.getDiskDevice(volumePath, true, true).first(); + + try { + logger.debug(LogUtils.logGsonWithoutException("Trying to change disk [%s] IOPS to [%s].", disk, newIops)); + VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); + VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); + + StorageIOAllocationInfo storageIOAllocation = new StorageIOAllocationInfo(); + storageIOAllocation.setLimit(newIops); + disk.setStorageIOAllocation(storageIOAllocation); + + deviceConfigSpec.setDevice(disk); + deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT); + vmConfigSpec.getDeviceChange().add(deviceConfigSpec); + vmMo.configureVm(vmConfigSpec); + } catch (Exception e) { + String vmwareDocumentation = "https://kb.vmware.com/s/article/68164"; + logger.error(LogUtils.logGsonWithoutException("Failed to change disk [%s] IOPS to [%s] due to [%s]. This happens when the disk controller is IDE." + + " Please read this documentation for more information: [%s]. ", disk, newIops, e.getMessage(), vmwareDocumentation), e); + } + } + private Pair getVirtualDiskInfo(VirtualMachineMO vmMo, String srcDiskName) throws Exception { Pair deviceInfo = vmMo.getDiskDevice(srcDiskName); if (deviceInfo == null) { diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java index d2d319ed9d03..cee2819db1d5 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java @@ -27,6 +27,7 @@ import javax.inject.Inject; import com.cloud.agent.api.to.DiskTO; +import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.Storage; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; @@ -38,6 +39,7 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.springframework.stereotype.Component; @@ -251,6 +253,25 @@ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, As , sourcePool , targetPool , hostIdForVmAndHostGuidInTargetCluster.second(), ((VolumeObjectTO) srcData.getTO()).getChainInfo()); + + VolumeInfo volume = (VolumeInfo) srcData; + if (volume.getpayload() instanceof DiskOfferingVO) { + DiskOfferingVO offering = (DiskOfferingVO) volume.getpayload(); + + Long offeringIopsReadRate = offering.getIopsReadRate(); + Long offeringIopsWriteRate = offering.getIopsWriteRate(); + + Long minIops = null; + Long maxIops = null; + if (ObjectUtils.allNotNull(offeringIopsReadRate, offeringIopsWriteRate)) { + minIops = Math.min(offeringIopsReadRate, offeringIopsWriteRate); + maxIops = Math.max(offeringIopsReadRate, offeringIopsWriteRate); + } + + cmd.setNewMinIops(minIops); + cmd.setNewMaxIops(maxIops); + } + if (sourcePool.getParent() != 0) { cmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); } diff --git a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java index 5faa377ce3d3..cad4ae0f4b62 100644 --- a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java @@ -469,6 +469,8 @@ public void resize(DataObject data, AsyncCompletionCallback cal } ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), vol.getSize(), resizeParameter.newSize, resizeParameter.shrinkOk, resizeParameter.instanceName, vol.getChainInfo(), vol.getPassphrase(), vol.getEncryptFormat()); + resizeCmd.setNewMinIops(resizeParameter.newMinIops); + resizeCmd.setNewMaxIops(resizeParameter.newMaxIops); if (pool.getParent() != 0) { resizeCmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); } diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index ca3d31d4fad3..a351a0daa274 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -1268,6 +1268,21 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep } else { newMinIops = newDiskOffering.getMinIops(); newMaxIops = newDiskOffering.getMaxIops(); + + if (newDiskOffering.getMinIops() != null) { + newMinIops = newDiskOffering.getMinIops(); + } + + if (newDiskOffering.getMaxIops() != null) { + newMaxIops = newDiskOffering.getMaxIops(); + } + + Long newDiskOfferingIopsReadRate = newDiskOffering.getIopsReadRate(); + Long newDiskOfferingIopsWriteRate = newDiskOffering.getIopsWriteRate(); + if (ObjectUtils.allNull(newMinIops, newMaxIops) && ObjectUtils.allNotNull(newDiskOfferingIopsReadRate, newDiskOfferingIopsWriteRate)) { + newMaxIops = Math.max(newDiskOfferingIopsReadRate, newDiskOfferingIopsWriteRate); + newMinIops = Math.min(newDiskOfferingIopsReadRate, newDiskOfferingIopsWriteRate); + } } // if the hypervisor snapshot reserve value is null, it must remain null (currently only KVM uses null and null is all KVM uses for a value here) @@ -1335,10 +1350,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep volumeMigrateRequired = true; } - boolean volumeResizeRequired = false; - if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) { - volumeResizeRequired = true; - } + boolean volumeResizeRequired = currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops()); if (!volumeMigrateRequired && !volumeResizeRequired && newDiskOffering != null) { _volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId()); volume = _volsDao.findById(volume.getId()); @@ -1403,7 +1415,14 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep } else if (jobResult instanceof Throwable) { throw new RuntimeException("Unexpected exception", (Throwable) jobResult); } else if (jobResult instanceof Long) { - return _volsDao.findById((Long) jobResult); + Long volumeId = (Long) jobResult; + if (newDiskOffering != null) { + _volsDao.updateDiskOffering(volumeId, newDiskOffering.getId()); + } + volume.setMinIops(newMinIops); + volume.setMinIops(newMaxIops); + _volsDao.update(volumeId, volume); + return _volsDao.findById(volumeId); } } @@ -3784,9 +3803,9 @@ private Volume orchestrateMigrateVolume(VolumeVO volume, StoragePool destPool, b Volume newVol = null; try { if (liveMigrateVolume) { - newVol = liveMigrateVolume(volume, destPool); + newVol = liveMigrateVolume(volume, destPool, newDiskOffering); } else { - newVol = _volumeMgr.migrateVolume(volume, destPool); + newVol = _volumeMgr.migrateVolume(volume, destPool, newDiskOffering); } if (newDiskOffering != null) { _volsDao.updateDiskOffering(newVol.getId(), newDiskOffering.getId()); @@ -3802,9 +3821,9 @@ private Volume orchestrateMigrateVolume(VolumeVO volume, StoragePool destPool, b } @DB - protected Volume liveMigrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException { + protected Volume liveMigrateVolume(Volume volume, StoragePool destPool, DiskOfferingVO newDiskOffering) throws StorageUnavailableException { VolumeInfo vol = volFactory.getVolume(volume.getId()); - + vol.addPayload(newDiskOffering); DataStore dataStoreTarget = dataStoreMgr.getDataStore(destPool.getId(), DataStoreRole.Primary); AsyncCallFuture future = volService.migrateVolume(vol, dataStoreTarget); try { diff --git a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java index 13fa2608016c..ac02f0df6e48 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -1038,7 +1038,7 @@ private UserVm migrateImportedVM(HostVO sourceHost, VirtualMachineTemplate templ if (vm.getState().equals(VirtualMachine.State.Running)) { volume = volumeManager.liveMigrateVolume(volumeVO, storagePool); } else { - volume = volumeManager.migrateVolume(volumeVO, storagePool); + volume = volumeManager.migrateVolume(volumeVO, storagePool, dOffering); } if (volume == null) { String msg = ""; diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index ebd8d0ed6db1..0e2cd6101853 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -2797,9 +2797,13 @@ public Pair getDiskDevice(String vmdkDatastorePath) throws } // return pair of VirtualDisk and disk device bus name(ide0:0, etc) - public Pair getDiskDevice(String vmdkDatastorePath, boolean matchExactly) throws Exception { + public Pair getDiskDevice(String vmdkDatastorePath, boolean matchExactly, boolean ignoreDotOnPath) throws Exception { List devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + if (ignoreDotOnPath) { + vmdkDatastorePath = vmdkDatastorePath + "."; + } + DatastoreFile dsSrcFile = new DatastoreFile(vmdkDatastorePath); String srcBaseName = dsSrcFile.getFileBaseName(); String trimmedSrcBaseName = VmwareHelper.trimSnapshotDeltaPostfix(srcBaseName);