From 388fdc2b3ee1e3c02f5e0bebdfe8167d3de788e6 Mon Sep 17 00:00:00 2001 From: Henrique Sato Date: Tue, 17 Mar 2026 19:39:04 -0300 Subject: [PATCH 1/2] [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); From e56a35ec3f5912677b548504671a5aac48d0103e Mon Sep 17 00:00:00 2001 From: Henrique Sato Date: Mon, 30 Mar 2026 18:19:44 -0300 Subject: [PATCH 2/2] Address reviews & adjusts --- .../api/storage/MigrateVolumeCommand.java | 20 +++--- .../api/storage/ResizeVolumeCommand.java | 27 ++++---- .../java/com/cloud/vm/VmWorkResizeVolume.java | 14 +++- .../vmware/resource/VmwareResource.java | 22 +++---- .../motion/VmwareStorageMotionStrategy.java | 16 ++--- .../CloudStackPrimaryDataStoreDriverImpl.java | 5 +- .../cloud/storage/ResizeVolumePayload.java | 8 ++- .../cloud/storage/VolumeApiServiceImpl.java | 64 ++++++++----------- 8 files changed, 87 insertions(+), 89 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 2d0f94e6a6c0..29db60cccde3 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,8 +36,8 @@ public class MigrateVolumeCommand extends Command { String attachedVmName; Volume.Type volumeType; String hostGuidInTargetCluster; - Long newMaxIops; - Long newMinIops; + Long newReadRateIops; + Long newWriteRateIops; private DataTO srcData; private DataTO destData; @@ -153,19 +153,19 @@ public boolean isReconcile() { return true; } - public Long getNewMinIops() { - return newMinIops; + public Long getNewWriteRateIops() { + return newWriteRateIops; } - public void setNewMinIops(Long newMinIops) { - this.newMinIops = newMinIops; + public void setNewWriteRateIops(Long newWriteRateIops) { + this.newWriteRateIops = newWriteRateIops; } - public Long getNewMaxIops() { - return newMaxIops; + public Long getNewReadRateIops() { + return newReadRateIops; } - public void setNewMaxIops(Long newMaxIops) { - this.newMaxIops = newMaxIops; + public void setNewReadRateIops(Long newReadRateIops) { + this.newReadRateIops = newReadRateIops; } } 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 a8d88ca3124d..f90d6544bdc3 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,8 +33,8 @@ public class ResizeVolumeCommand extends Command { private boolean shrinkOk; private String vmInstance; private String chainInfo; - private Long newMaxIops; - private Long newMinIops; + private Long newReadRateIops; + private Long newWriteRateIops; /* For managed storage */ private boolean managed; @@ -76,6 +76,13 @@ public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, L this.managed = isManaged; } + public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, + String chainInfo, byte[] passphrase, String encryptFormat, Long newReadRateIops, Long newWriteRateIops) { + this(path, pool, currentSize, newSize, shrinkOk, vmInstance, chainInfo, passphrase, encryptFormat); + this.newReadRateIops = newReadRateIops; + this.newWriteRateIops = newWriteRateIops; + } + public String getPath() { return path; } @@ -122,19 +129,11 @@ public boolean executeInSequence() { return false; } - public Long getNewMaxIops() { - return newMaxIops; - } - - public void setNewMaxIops(Long newMaxIops) { - this.newMaxIops = newMaxIops; - } - - public Long getNewMinIops() { - return newMinIops; + public Long getNewReadRateIops() { + return newReadRateIops; } - public void setNewMinIops(Long newMinIops) { - this.newMinIops = newMinIops; + public Long getNewWriteRateIops() { + return newWriteRateIops; } } diff --git a/engine/components-api/src/main/java/com/cloud/vm/VmWorkResizeVolume.java b/engine/components-api/src/main/java/com/cloud/vm/VmWorkResizeVolume.java index de049b3f0b6d..4cd107763750 100644 --- a/engine/components-api/src/main/java/com/cloud/vm/VmWorkResizeVolume.java +++ b/engine/components-api/src/main/java/com/cloud/vm/VmWorkResizeVolume.java @@ -27,9 +27,11 @@ public class VmWorkResizeVolume extends VmWork { private Integer newHypervisorSnapshotReserve; private Long newServiceOfferingId; private boolean shrinkOk; + private Long newReadRateIops; + private Long newWriteRateIops; public VmWorkResizeVolume(long userId, long accountId, long vmId, String handlerName, long volumeId, long currentSize, long newSize, - Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, Long newServiceOfferingId, boolean shrinkOk) { + Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, Long newServiceOfferingId, boolean shrinkOk, Long newReadRateIops, Long newWriteRateIops) { super(userId, accountId, vmId, handlerName); this.volumeId = volumeId; @@ -40,6 +42,8 @@ public VmWorkResizeVolume(long userId, long accountId, long vmId, String handler this.newHypervisorSnapshotReserve = newHypervisorSnapshotReserve; this.newServiceOfferingId = newServiceOfferingId; this.shrinkOk = shrinkOk; + this.newReadRateIops = newReadRateIops; + this.newWriteRateIops = newWriteRateIops; } public long getVolumeId() { @@ -71,4 +75,12 @@ public boolean isShrinkOk() { } public Integer getNewHypervisorSnapshotReserve() { return newHypervisorSnapshotReserve; } + + public Long getNewReadRateIops() { + return newReadRateIops; + } + + public Long getNewWriteRateIops() { + return newWriteRateIops; + } } 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 ff0fe10fbb40..e627251bc052 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 @@ -876,8 +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(); + Long newReadRateIops = cmd.getNewReadRateIops(); + Long newWriteRateIops = cmd.getNewWriteRateIops(); boolean useWorkerVm = false; VmwareContext context = getServiceContext(); @@ -985,7 +985,7 @@ private Answer execute(ResizeVolumeCommand cmd) { VirtualDisk disk = getDiskAfterResizeDiskValidations(vmMo, path); String vmdkAbsFile = VmwareHelper.getAbsoluteVmdkFile(disk); - setDiskIops(disk, newMinIops, newMaxIops); + setDiskIops(disk, newReadRateIops, newWriteRateIops); if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) { vmMo.updateAdapterTypeIfRequired(vmdkAbsFile); @@ -1039,14 +1039,14 @@ 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). + * Sets the disk IOPS which is the sum of read rate IOPS and write rate IOPS; if they are null, the IOPS limit is set to -1 (unlimited). */ - private void setDiskIops(VirtualDisk disk, Long newMinIops, Long newMaxIops) { + private void setDiskIops(VirtualDisk disk, Long newReadRateIops, Long newWriteRateIops) { StorageIOAllocationInfo storageIOAllocation = new StorageIOAllocationInfo(); Long iops = -1L; - if (ObjectUtils.allNotNull(newMinIops, newMaxIops) && newMinIops > 0 && newMaxIops > 0) { - iops = newMinIops + newMaxIops; + if (ObjectUtils.allNotNull(newReadRateIops, newWriteRateIops) && newReadRateIops > 0 && newWriteRateIops > 0) { + iops = newReadRateIops + newWriteRateIops; } storageIOAllocation.setLimit(iops); @@ -5218,11 +5218,11 @@ private Answer execute(MigrateVolumeCommand cmd) { */ private void setDiskIops(MigrateVolumeCommand cmd, VirtualMachineMO vmMo, String volumePath) throws Exception { Long newIops = -1L; - Long newMinIops = cmd.getNewMinIops(); - Long newMaxIops = cmd.getNewMaxIops(); + Long readRateIops = cmd.getNewReadRateIops(); + Long writeRateIops = cmd.getNewWriteRateIops(); - if (ObjectUtils.allNotNull(newMinIops, newMaxIops) && newMinIops > 0 && newMaxIops > 0) { - newIops = newMinIops + newMaxIops; + if (ObjectUtils.allNotNull(readRateIops, writeRateIops) && readRateIops > 0 && writeRateIops > 0) { + newIops = readRateIops + writeRateIops; } VirtualDisk disk = vmMo.getDiskDevice(volumePath, true, true).first(); 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 cee2819db1d5..12760611899c 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 @@ -39,7 +39,6 @@ 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; @@ -258,18 +257,11 @@ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, As if (volume.getpayload() instanceof DiskOfferingVO) { DiskOfferingVO offering = (DiskOfferingVO) volume.getpayload(); - Long offeringIopsReadRate = offering.getIopsReadRate(); - Long offeringIopsWriteRate = offering.getIopsWriteRate(); + Long offeringReadRateIops = offering.getIopsReadRate(); + Long offeringWriteRateIops = 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); + cmd.setNewReadRateIops(offeringReadRateIops); + cmd.setNewWriteRateIops(offeringWriteRateIops); } if (sourcePool.getParent() != 0) { 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 cad4ae0f4b62..a4f90c8bbe80 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 @@ -468,9 +468,8 @@ public void resize(DataObject data, AsyncCompletionCallback cal endpointsToRunResize = new long[] {ep.getId()}; } 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); + resizeParameter.newSize, resizeParameter.shrinkOk, resizeParameter.instanceName, vol.getChainInfo(), vol.getPassphrase(), vol.getEncryptFormat(), + resizeParameter.newReadRateIops, resizeParameter.newWriteRateIops); if (pool.getParent() != 0) { resizeCmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); } diff --git a/server/src/main/java/com/cloud/storage/ResizeVolumePayload.java b/server/src/main/java/com/cloud/storage/ResizeVolumePayload.java index 32aa09be8b63..61f1d6d5b784 100644 --- a/server/src/main/java/com/cloud/storage/ResizeVolumePayload.java +++ b/server/src/main/java/com/cloud/storage/ResizeVolumePayload.java @@ -22,6 +22,8 @@ public class ResizeVolumePayload { public final Long newMinIops; public final Long newMaxIops; public Long newDiskOfferingId; + public Long newReadRateIops; + public Long newWriteRateIops; public final Integer newHypervisorSnapshotReserve; public final boolean shrinkOk; public final String instanceName; @@ -41,10 +43,12 @@ public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, Integ this.newDiskOfferingId = null; } - public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, Long newDiskOfferingId, Integer newHypervisorSnapshotReserve, boolean shrinkOk, - String instanceName, long[] hosts, boolean isManaged) { + public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, Long newDiskOfferingId, Long newReadRateIops, Long newWriteRateIops, + Integer newHypervisorSnapshotReserve, boolean shrinkOk, String instanceName, long[] hosts, boolean isManaged) { this(newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, shrinkOk, instanceName, hosts, isManaged); this.newDiskOfferingId = newDiskOfferingId; + this.newReadRateIops = newReadRateIops; + this.newWriteRateIops = newWriteRateIops; } public Long getNewDiskOfferingId() { diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index a351a0daa274..921faa0f29b5 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -1118,6 +1118,8 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep Long newSize = cmd.getSize(); Long newMinIops = cmd.getMinIops(); Long newMaxIops = cmd.getMaxIops(); + Long newReadRateIops = null; + Long newWriteRateIops = null; Integer newHypervisorSnapshotReserve = null; boolean shrinkOk = cmd.isShrinkOk(); boolean autoMigrateVolume = cmd.getAutoMigrate(); @@ -1268,23 +1270,11 @@ 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); - } } + newReadRateIops = ObjectUtils.defaultIfNull(newDiskOffering.getIopsReadRate(), 0L); + newWriteRateIops = ObjectUtils.defaultIfNull(newDiskOffering.getIopsWriteRate(), 0L); + // 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) newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve() != null ? newDiskOffering.getHypervisorSnapshotReserve() : null; } @@ -1351,7 +1341,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep } boolean volumeResizeRequired = currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops()); - if (!volumeMigrateRequired && !volumeResizeRequired && newDiskOffering != null) { + if (!volumeMigrateRequired && !volumeResizeRequired && newDiskOffering != null && !HypervisorType.VMware.equals(hypervisorType)) { _volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId()); volume = _volsDao.findById(volume.getId()); updateStorageWithTheNewDiskOffering(volume, newDiskOffering); @@ -1387,13 +1377,13 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep try { return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, - newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); + newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk, newReadRateIops, newWriteRateIops); } finally { _workJobDao.expunge(placeHolder.getId()); } } else { Outcome outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, - newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); + newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk, newReadRateIops, newWriteRateIops); try { outcome.get(); @@ -1415,14 +1405,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep } else if (jobResult instanceof Throwable) { throw new RuntimeException("Unexpected exception", (Throwable) jobResult); } else if (jobResult instanceof Long) { - 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); + return _volsDao.findById((Long) jobResult); } } @@ -1431,7 +1414,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep } return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, - shrinkOk); + shrinkOk, newWriteRateIops, newReadRateIops); } protected void validateNoVmSnapshots(VolumeVO volume) { @@ -1502,7 +1485,7 @@ private void validateIops(Long minIops, Long maxIops, Storage.StoragePoolType po } private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, Long newDiskOfferingId, - boolean shrinkOk) { + boolean shrinkOk, Long newReadRateIops, Long newWriteRateIops) { VolumeVO volume = _volsDao.findById(volumeId); UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); @@ -1560,7 +1543,7 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n } } - ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, newDiskOfferingId, newHypervisorSnapshotReserve, shrinkOk, instanceName, hosts, isManaged); + ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, newDiskOfferingId, newReadRateIops, newWriteRateIops, newHypervisorSnapshotReserve, shrinkOk, instanceName, hosts, isManaged); try { VolumeInfo vol = volFactory.getVolume(volume.getId()); @@ -2256,6 +2239,15 @@ private boolean compareEqualsIncludingNullOrZero(Long a, Long b) { private VolumeVO resizeVolumeInternal(VolumeVO volume, DiskOfferingVO newDiskOffering, Long currentSize, Long newSize, Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, boolean shrinkOk) throws ResourceAllocationException { UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); HypervisorType hypervisorType = _volsDao.getHypervisorType(volume.getId()); + Long newDiskOfferingId = null; + Long newDiskOfferingReadRateIops = null; + Long newDiskOfferingWriteRateIops = null; + + if (newDiskOffering != null) { + newDiskOfferingId = newDiskOffering.getId(); + newDiskOfferingReadRateIops = newDiskOffering.getIopsReadRate(); + newDiskOfferingWriteRateIops = newDiskOffering.getIopsWriteRate(); + } if (userVm != null) { if (volume.getVolumeType().equals(Volume.Type.ROOT) && userVm.getPowerState() != VirtualMachine.PowerState.PowerOff && hypervisorType == HypervisorType.VMware) { @@ -2274,13 +2266,13 @@ private VolumeVO resizeVolumeInternal(VolumeVO volume, DiskOfferingVO newDiskOff try { return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, - newDiskOffering != null ? newDiskOffering.getId() : null, shrinkOk); + newDiskOfferingId, shrinkOk, newDiskOfferingReadRateIops, newDiskOfferingWriteRateIops); } finally { _workJobDao.expunge(placeHolder.getId()); } } else { Outcome outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, - newDiskOffering != null ? newDiskOffering.getId() : null, shrinkOk); + newDiskOffering != null ? newDiskOffering.getId() : null, shrinkOk, newDiskOfferingReadRateIops, newDiskOfferingWriteRateIops); try { outcome.get(); @@ -2310,8 +2302,8 @@ private VolumeVO resizeVolumeInternal(VolumeVO volume, DiskOfferingVO newDiskOff } } - return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? newDiskOffering.getId() : null, - shrinkOk); + return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOfferingId, + shrinkOk, newDiskOfferingReadRateIops, newDiskOfferingWriteRateIops); } private void validateVolumeReadyStateAndHypervisorChecks(VolumeVO volume, long currentSize, Long newSize) { @@ -5165,7 +5157,7 @@ public Outcome detachVolumeFromVmThroughJobQueue(final Long vmId, final } public Outcome resizeVolumeThroughJobQueue(final Long vmId, final long volumeId, final long currentSize, final long newSize, final Long newMinIops, final Long newMaxIops, - final Integer newHypervisorSnapshotReserve, final Long newServiceOfferingId, final boolean shrinkOk) { + final Integer newHypervisorSnapshotReserve, final Long newServiceOfferingId, final boolean shrinkOk, final Long newReadRateIops, final Long newWriteRateIops) { final CallContext context = CallContext.current(); final User callingUser = context.getCallingUser(); final Account callingAccount = context.getCallingAccount(); @@ -5186,7 +5178,7 @@ public Outcome resizeVolumeThroughJobQueue(final Long vmId, final long v // save work context info (there are some duplications) VmWorkResizeVolume workInfo = new VmWorkResizeVolume(callingUser.getId(), callingAccount.getId(), vm.getId(), VolumeApiServiceImpl.VM_WORK_JOB_HANDLER, volumeId, currentSize, newSize, - newMinIops, newMaxIops, newHypervisorSnapshotReserve, newServiceOfferingId, shrinkOk); + newMinIops, newMaxIops, newHypervisorSnapshotReserve, newServiceOfferingId, shrinkOk, newReadRateIops, newWriteRateIops); workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); @@ -5313,7 +5305,7 @@ private Pair orchestrateDetachVolumeFromVM(VmWorkDetachV @ReflectionUse private Pair orchestrateResizeVolume(VmWorkResizeVolume work) throws Exception { Volume vol = orchestrateResizeVolume(work.getVolumeId(), work.getCurrentSize(), work.getNewSize(), work.getNewMinIops(), work.getNewMaxIops(), work.getNewHypervisorSnapshotReserve(), - work.getNewServiceOfferingId(), work.isShrinkOk()); + work.getNewServiceOfferingId(), work.isShrinkOk(), work.getNewReadRateIops(), work.getNewWriteRateIops()); return new Pair(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(new Long(vol.getId()))); }