Skip to content

Commit 5ac7a39

Browse files
committed
Merge remote-tracking branch 'origin/vmware-apply-iops-in-resize-migrate' into vmware-apply-iops-in-resize-migrate
2 parents 120a436 + 1684347 commit 5ac7a39

File tree

11 files changed

+129
-22
lines changed

11 files changed

+129
-22
lines changed

core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class MigrateVolumeCommand extends Command {
3636
String attachedVmName;
3737
Volume.Type volumeType;
3838
String hostGuidInTargetCluster;
39+
Long newIops;
3940

4041
private DataTO srcData;
4142
private DataTO destData;
@@ -146,6 +147,14 @@ public int getWaitInMillSeconds() {
146147

147148
public String getChainInfo() { return chainInfo; }
148149

150+
public void setNewIops(Long newIops) {
151+
this.newIops = newIops;
152+
}
153+
154+
public Long getNewIops() {
155+
return newIops;
156+
}
157+
149158
@Override
150159
public boolean isReconcile() {
151160
return true;

core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public class ResizeVolumeCommand extends Command {
3333
private boolean shrinkOk;
3434
private String vmInstance;
3535
private String chainInfo;
36+
private Long newMaxIops;
37+
private Long newMinIops;
3638

3739
/* For managed storage */
3840
private boolean managed;
@@ -70,7 +72,6 @@ public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, L
7072
public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance,
7173
boolean isManaged, String iScsiName) {
7274
this(path, pool, currentSize, newSize, shrinkOk, vmInstance);
73-
7475
this.iScsiName = iScsiName;
7576
this.managed = isManaged;
7677
}
@@ -120,4 +121,20 @@ public void clearPassphrase() {
120121
public boolean executeInSequence() {
121122
return false;
122123
}
124+
125+
public Long getNewMaxIops() {
126+
return newMaxIops;
127+
}
128+
129+
public void setNewMaxIops(Long newMaxIops) {
130+
this.newMaxIops = newMaxIops;
131+
}
132+
133+
public Long getNewMinIops() {
134+
return newMinIops;
135+
}
136+
137+
public void setNewMinIops(Long newMinIops) {
138+
this.newMinIops = newMinIops;
139+
}
123140
}

engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId,
111111

112112
VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, UserVm vm) throws StorageUnavailableException;
113113

114-
Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException;
114+
Volume migrateVolume(Volume volume, StoragePool destPool, DiskOffering newDiskOffering) throws StorageUnavailableException;
115115

116116
Volume liveMigrateVolume(Volume volume, StoragePool destPool);
117117

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ public VolumeInfo moveVolume(VolumeInfo volumeInfo, long destPoolDcId, Long dest
329329
throw new CloudRuntimeException(String.format("Failed to find a storage pool with enough capacity to move the volume [%s] to.", volumeToString));
330330
}
331331

332-
Volume newVol = migrateVolume(volumeInfo, destPool);
332+
Volume newVol = migrateVolume(volumeInfo, destPool, diskOffering);
333333
return volFactory.getVolume(newVol.getId());
334334
}
335335

@@ -1419,13 +1419,14 @@ private void checkConcurrentJobsPerDatastoreThreshhold(final StoragePool destPoo
14191419

14201420
@Override
14211421
@DB
1422-
public Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException {
1422+
public Volume migrateVolume(Volume volume, StoragePool destPool, DiskOffering newDiskOffering) throws StorageUnavailableException {
14231423
String volumeToString = getVolumeIdentificationInfos(volume);
14241424

14251425
VolumeInfo vol = volFactory.getVolume(volume.getId());
14261426
if (vol == null) {
14271427
throw new CloudRuntimeException(String.format("Volume migration failed because volume [%s] is null.", volumeToString));
14281428
}
1429+
vol.addPayload(newDiskOffering);
14291430
if (destPool == null) {
14301431
throw new CloudRuntimeException("Volume migration failed because the destination storage pool is not available.");
14311432
}
@@ -1554,7 +1555,7 @@ public boolean storageMigration(VirtualMachineProfile vm, Map<Volume, StoragePoo
15541555
}
15551556
logger.debug("Offline VM migration was not done up the stack in VirtualMachineManager. Trying to migrate the VM here.");
15561557
for (Map.Entry<Volume, StoragePool> entry : volumeStoragePoolMap.entrySet()) {
1557-
Volume result = migrateVolume(entry.getKey(), entry.getValue());
1558+
Volume result = migrateVolume(entry.getKey(), entry.getValue(), null);
15581559
if (result == null) {
15591560
return false;
15601561
}
@@ -2019,7 +2020,7 @@ public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws Sto
20192020
} else if (task.type == VolumeTaskType.MIGRATE) {
20202021
store = (PrimaryDataStore) dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary);
20212022
updateVolumeSize(store, task.volume);
2022-
vol = migrateVolume(task.volume, store);
2023+
vol = migrateVolume(task.volume, store, null);
20232024
} else if (task.type == VolumeTaskType.RECREATE) {
20242025
Pair<VolumeVO, DataStore> result = recreateVolume(task.volume, vm, dest);
20252026
store = (PrimaryDataStore) dataStoreMgr.getDataStore(result.second().getId(), DataStoreRole.Primary);

engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import com.cloud.storage.ScopeType;
7575
import com.cloud.storage.Snapshot.Type;
7676
import com.cloud.storage.SnapshotVO;
77+
import com.cloud.storage.DiskOfferingVO;
7778
import com.cloud.storage.StorageManager;
7879
import com.cloud.storage.Storage.StoragePoolType;
7980
import com.cloud.storage.StoragePool;
@@ -546,6 +547,16 @@ protected Answer migrateVolumeToPool(DataObject srcData, DataObject destData) {
546547
StoragePool srcPool = (StoragePool)dataStoreMgr.getDataStore(srcData.getDataStore().getId(), DataStoreRole.Primary);
547548
StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(destData.getDataStore().getId(), DataStoreRole.Primary);
548549
MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool, volume.getAttachedVmName(), volume.getVolumeType(), waitInterval, volume.getChainInfo());
550+
551+
if (volume.getpayload() instanceof DiskOfferingVO) {
552+
DiskOfferingVO offering = (DiskOfferingVO) volume.getpayload();
553+
Long newIops = null;
554+
if (offering.getIopsReadRate() != null && offering.getIopsWriteRate() != null) {
555+
newIops = offering.getIopsReadRate() + offering.getIopsWriteRate();
556+
}
557+
command.setNewIops(newIops);
558+
}
559+
549560
if (srcPool.getParent() != 0) {
550561
command.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString());
551562
}

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.UUID;
4646
import java.util.stream.Collectors;
4747

48+
import com.vmware.vim25.StorageIOAllocationInfo;
4849
import com.cloud.agent.api.CleanupVMCommand;
4950
import javax.naming.ConfigurationException;
5051
import javax.xml.datatype.XMLGregorianCalendar;
@@ -78,6 +79,7 @@
7879
import org.apache.commons.lang.ArrayUtils;
7980
import org.apache.commons.lang.math.NumberUtils;
8081
import org.apache.logging.log4j.ThreadContext;
82+
import org.apache.commons.lang3.ObjectUtils;
8183
import org.joda.time.Duration;
8284

8385
import com.cloud.agent.IAgentControl;
@@ -874,6 +876,8 @@ private Answer execute(ResizeVolumeCommand cmd) {
874876
boolean managed = cmd.isManaged();
875877
String poolUUID = cmd.getPoolUuid();
876878
String chainInfo = cmd.getChainInfo();
879+
Long newMinIops = cmd.getNewMinIops();
880+
Long newMaxIops = cmd.getNewMaxIops();
877881
boolean useWorkerVm = false;
878882

879883
VmwareContext context = getServiceContext();
@@ -888,8 +892,6 @@ private Answer execute(ResizeVolumeCommand cmd) {
888892
oldSize / (float) ResourceType.bytesToMiB, newSize / (float) ResourceType.bytesToMiB, vmName);
889893
logger.error(errorMsg);
890894
throw new Exception(errorMsg);
891-
} else if (newSize == oldSize) {
892-
return new ResizeVolumeAnswer(cmd, true, "success", newSize * ResourceType.bytesToKiB);
893895
}
894896

895897
if (vmName.equalsIgnoreCase("none")) {
@@ -983,6 +985,8 @@ private Answer execute(ResizeVolumeCommand cmd) {
983985
VirtualDisk disk = getDiskAfterResizeDiskValidations(vmMo, path);
984986
String vmdkAbsFile = VmwareHelper.getAbsoluteVmdkFile(disk);
985987

988+
setDiskIops(disk, newMinIops, newMaxIops);
989+
986990
if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) {
987991
vmMo.updateAdapterTypeIfRequired(vmdkAbsFile);
988992
}
@@ -1034,6 +1038,22 @@ private Answer execute(ResizeVolumeCommand cmd) {
10341038
}
10351039
}
10361040

1041+
/**
1042+
* 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).
1043+
*/
1044+
private void setDiskIops(VirtualDisk disk, Long newMinIops, Long newMaxIops) {
1045+
StorageIOAllocationInfo storageIOAllocation = new StorageIOAllocationInfo();
1046+
Long iops = -1L;
1047+
1048+
if (ObjectUtils.allNotNull(newMinIops, newMaxIops) && newMinIops > 0 && newMaxIops > 0) {
1049+
iops = newMinIops + newMaxIops;
1050+
}
1051+
1052+
storageIOAllocation.setLimit(iops);
1053+
logger.debug(LogUtils.logGsonWithoutException("Setting [%s] as the IOPS limit of disk [%s].", iops == -1L ? "unlimited" : iops, disk));
1054+
disk.setStorageIOAllocation(storageIOAllocation);
1055+
}
1056+
10371057
private VirtualDisk getDiskAfterResizeDiskValidations(VirtualMachineMO vmMo, String volumePath) throws Exception {
10381058
Pair<VirtualDisk, String> vdisk = vmMo.getDiskDevice(volumePath);
10391059
if (vdisk == null) {
@@ -4426,7 +4446,7 @@ protected GetVolumeStatsAnswer execute(GetVolumeStatsCommand cmd) {
44264446
for (String diskPath : disks) {
44274447
DatastoreFile file = new DatastoreFile(diskPath);
44284448
VirtualMachineMO vmMo = dcMo.findVm(file.getDir());
4429-
Pair<VirtualDisk, String> vds = vmMo.getDiskDevice(file.getFileName(), true);
4449+
Pair<VirtualDisk, String> vds = vmMo.getDiskDevice(file.getFileName(), true, false);
44304450
long virtualsize = vds.first().getCapacityInKB() * 1024;
44314451
long physicalsize = primaryStorageDatastoreMo.fileDiskSize(file.getPath());
44324452
if (statEntry.containsKey(chainInfo)) {
@@ -5179,6 +5199,8 @@ private Answer execute(MigrateVolumeCommand cmd) {
51795199
volumePath = vmMo.getVmdkFileBaseName(disk);
51805200
}
51815201
}
5202+
5203+
setDiskIops(cmd, vmMo, volumePath);
51825204
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
51835205
chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, targetDsMo.getName()));
51845206
MigrateVolumeAnswer answer = new MigrateVolumeAnswer(cmd, true, null, volumePath);
@@ -5191,6 +5213,33 @@ private Answer execute(MigrateVolumeCommand cmd) {
51915213
}
51925214
}
51935215

5216+
/**
5217+
* Sets the disk IOPS limitation, if the {@link MigrateVolumeCommand} did not specify this limitation, then it is set to -1 (unlimited).
5218+
*/
5219+
private void setDiskIops(MigrateVolumeCommand cmd, VirtualMachineMO vmMo, String volumePath) throws Exception {
5220+
Long newIops = cmd.getNewIops() == null ? -1L : cmd.getNewIops();
5221+
VirtualDisk disk = vmMo.getDiskDevice(volumePath, true, true).first();
5222+
5223+
try {
5224+
logger.debug(LogUtils.logGsonWithoutException("Trying to change disk [%s] IOPS to [%s].", disk, newIops));
5225+
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
5226+
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
5227+
5228+
StorageIOAllocationInfo storageIOAllocation = new StorageIOAllocationInfo();
5229+
storageIOAllocation.setLimit(newIops);
5230+
disk.setStorageIOAllocation(storageIOAllocation);
5231+
5232+
deviceConfigSpec.setDevice(disk);
5233+
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
5234+
vmConfigSpec.getDeviceChange().add(deviceConfigSpec);
5235+
vmMo.configureVm(vmConfigSpec);
5236+
} catch (Exception e) {
5237+
String vmwareDocumentation = "https://kb.vmware.com/s/article/68164";
5238+
logger.error(LogUtils.logGsonWithoutException("Failed to change disk [%s] IOPS to [%s] due to [%s]. This happens when the disk controller is IDE." +
5239+
" Please read this documentation for more information: [%s]. ", disk, newIops, e.getMessage(), vmwareDocumentation), e);
5240+
}
5241+
}
5242+
51945243
private Pair<VirtualDisk, String> getVirtualDiskInfo(VirtualMachineMO vmMo, String srcDiskName) throws Exception {
51955244
Pair<VirtualDisk, String> deviceInfo = vmMo.getDiskDevice(srcDiskName);
51965245
if (deviceInfo == null) {

plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import javax.inject.Inject;
2828

2929
import com.cloud.agent.api.to.DiskTO;
30+
import com.cloud.storage.DiskOfferingVO;
3031
import com.cloud.storage.Storage;
3132
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
3233
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
@@ -251,6 +252,17 @@ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, As
251252
, sourcePool
252253
, targetPool
253254
, hostIdForVmAndHostGuidInTargetCluster.second(), ((VolumeObjectTO) srcData.getTO()).getChainInfo());
255+
256+
VolumeInfo volumeInfo = (VolumeInfo) srcData;
257+
if (volumeInfo.getpayload() instanceof DiskOfferingVO) {
258+
DiskOfferingVO offering = (DiskOfferingVO) volumeInfo.getpayload();
259+
Long newIops = null;
260+
if (offering.getIopsReadRate() != null && offering.getIopsWriteRate() != null) {
261+
newIops = offering.getIopsReadRate() + offering.getIopsWriteRate();
262+
}
263+
cmd.setNewIops(newIops);
264+
}
265+
254266
if (sourcePool.getParent() != 0) {
255267
cmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString());
256268
}

plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,8 @@ public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> cal
469469
}
470470
ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), vol.getSize(),
471471
resizeParameter.newSize, resizeParameter.shrinkOk, resizeParameter.instanceName, vol.getChainInfo(), vol.getPassphrase(), vol.getEncryptFormat());
472+
resizeCmd.setNewMinIops(resizeParameter.newMinIops);
473+
resizeCmd.setNewMaxIops(resizeParameter.newMaxIops);
472474
if (pool.getParent() != 0) {
473475
resizeCmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString());
474476
}

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,8 +1266,8 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep
12661266

12671267
validateIops(newMinIops, newMaxIops, volume.getPoolType());
12681268
} else {
1269-
newMinIops = newDiskOffering.getMinIops();
1270-
newMaxIops = newDiskOffering.getMaxIops();
1269+
newMinIops = newDiskOffering.getMinIops() != null ? newDiskOffering.getMinIops() : newDiskOffering.getIopsReadRate();
1270+
newMaxIops = newDiskOffering.getMaxIops() != null ? newDiskOffering.getMaxIops() : newDiskOffering.getIopsWriteRate();
12711271
}
12721272

12731273
// 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 +1335,8 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep
13351335
volumeMigrateRequired = true;
13361336
}
13371337

1338-
boolean volumeResizeRequired = false;
1339-
if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) {
1340-
volumeResizeRequired = true;
1341-
}
1338+
boolean volumeResizeRequired = currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())
1339+
|| !compareEqualsIncludingNullOrZero(newMaxIops, diskOffering.getIopsWriteRate()) || !compareEqualsIncludingNullOrZero(newMinIops, diskOffering.getIopsReadRate());
13421340
if (!volumeMigrateRequired && !volumeResizeRequired && newDiskOffering != null) {
13431341
_volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId());
13441342
volume = _volsDao.findById(volume.getId());
@@ -1403,7 +1401,11 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep
14031401
} else if (jobResult instanceof Throwable) {
14041402
throw new RuntimeException("Unexpected exception", (Throwable) jobResult);
14051403
} else if (jobResult instanceof Long) {
1406-
return _volsDao.findById((Long) jobResult);
1404+
Long volumeId = (Long) jobResult;
1405+
if (newDiskOffering != null) {
1406+
_volsDao.updateDiskOffering(volumeId, newDiskOffering.getId());
1407+
}
1408+
return _volsDao.findById(volumeId);
14071409
}
14081410
}
14091411

@@ -3784,9 +3786,9 @@ private Volume orchestrateMigrateVolume(VolumeVO volume, StoragePool destPool, b
37843786
Volume newVol = null;
37853787
try {
37863788
if (liveMigrateVolume) {
3787-
newVol = liveMigrateVolume(volume, destPool);
3789+
newVol = liveMigrateVolume(volume, destPool, newDiskOffering);
37883790
} else {
3789-
newVol = _volumeMgr.migrateVolume(volume, destPool);
3791+
newVol = _volumeMgr.migrateVolume(volume, destPool, newDiskOffering);
37903792
}
37913793
if (newDiskOffering != null) {
37923794
_volsDao.updateDiskOffering(newVol.getId(), newDiskOffering.getId());
@@ -3802,9 +3804,9 @@ private Volume orchestrateMigrateVolume(VolumeVO volume, StoragePool destPool, b
38023804
}
38033805

38043806
@DB
3805-
protected Volume liveMigrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException {
3807+
protected Volume liveMigrateVolume(Volume volume, StoragePool destPool, DiskOfferingVO newDiskOffering) throws StorageUnavailableException {
38063808
VolumeInfo vol = volFactory.getVolume(volume.getId());
3807-
3809+
vol.addPayload(newDiskOffering);
38083810
DataStore dataStoreTarget = dataStoreMgr.getDataStore(destPool.getId(), DataStoreRole.Primary);
38093811
AsyncCallFuture<VolumeApiResult> future = volService.migrateVolume(vol, dataStoreTarget);
38103812
try {

server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ private UserVm migrateImportedVM(HostVO sourceHost, VirtualMachineTemplate templ
10381038
if (vm.getState().equals(VirtualMachine.State.Running)) {
10391039
volume = volumeManager.liveMigrateVolume(volumeVO, storagePool);
10401040
} else {
1041-
volume = volumeManager.migrateVolume(volumeVO, storagePool);
1041+
volume = volumeManager.migrateVolume(volumeVO, storagePool, dOffering);
10421042
}
10431043
if (volume == null) {
10441044
String msg = "";

0 commit comments

Comments
 (0)