Skip to content

Commit 730cc5d

Browse files
authored
Change iops on offering change (#8872)
* Change IOPS on disk offering change * Remove iops & bandwidth limits before copying template * minor refactor * Handle diskOfferingDetails * Fixup
1 parent c24c1a5 commit 730cc5d

File tree

6 files changed

+129
-47
lines changed

6 files changed

+129
-47
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Lon
130130

131131
boolean canVmRestartOnAnotherServer(long vmId);
132132

133+
void saveVolumeDetails(Long diskOfferingId, Long volumeId);
134+
133135
/**
134136
* Allocate a volume or multiple volumes in case of template is registered with the 'deploy-as-is' option, allowing multiple disks
135137
*/

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

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -863,18 +863,7 @@ public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offeri
863863
vol.setFormat(getSupportedImageFormatForCluster(vm.getHypervisorType()));
864864
vol = _volsDao.persist(vol);
865865

866-
List<VolumeDetailVO> volumeDetailsVO = new ArrayList<VolumeDetailVO>();
867-
DiskOfferingDetailVO bandwidthLimitDetail = _diskOfferingDetailDao.findDetail(offering.getId(), Volume.BANDWIDTH_LIMIT_IN_MBPS);
868-
if (bandwidthLimitDetail != null) {
869-
volumeDetailsVO.add(new VolumeDetailVO(vol.getId(), Volume.BANDWIDTH_LIMIT_IN_MBPS, bandwidthLimitDetail.getValue(), false));
870-
}
871-
DiskOfferingDetailVO iopsLimitDetail = _diskOfferingDetailDao.findDetail(offering.getId(), Volume.IOPS_LIMIT);
872-
if (iopsLimitDetail != null) {
873-
volumeDetailsVO.add(new VolumeDetailVO(vol.getId(), Volume.IOPS_LIMIT, iopsLimitDetail.getValue(), false));
874-
}
875-
if (!volumeDetailsVO.isEmpty()) {
876-
_volDetailDao.saveDetails(volumeDetailsVO);
877-
}
866+
saveVolumeDetails(offering.getId(), vol.getId());
878867

879868
// Save usage event and update resource count for user vm volumes
880869
if (vm.getType() == VirtualMachine.Type.User) {
@@ -891,6 +880,32 @@ public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offeri
891880
return diskProfile;
892881
}
893882

883+
@Override
884+
public void saveVolumeDetails(Long diskOfferingId, Long volumeId) {
885+
List<VolumeDetailVO> volumeDetailsVO = new ArrayList<>();
886+
DiskOfferingDetailVO bandwidthLimitDetail = _diskOfferingDetailDao.findDetail(diskOfferingId, Volume.BANDWIDTH_LIMIT_IN_MBPS);
887+
if (bandwidthLimitDetail != null) {
888+
volumeDetailsVO.add(new VolumeDetailVO(volumeId, Volume.BANDWIDTH_LIMIT_IN_MBPS, bandwidthLimitDetail.getValue(), false));
889+
} else {
890+
VolumeDetailVO bandwidthLimit = _volDetailDao.findDetail(volumeId, Volume.BANDWIDTH_LIMIT_IN_MBPS);
891+
if (bandwidthLimit != null) {
892+
_volDetailDao.remove(bandwidthLimit.getId());
893+
}
894+
}
895+
DiskOfferingDetailVO iopsLimitDetail = _diskOfferingDetailDao.findDetail(diskOfferingId, Volume.IOPS_LIMIT);
896+
if (iopsLimitDetail != null) {
897+
volumeDetailsVO.add(new VolumeDetailVO(volumeId, Volume.IOPS_LIMIT, iopsLimitDetail.getValue(), false));
898+
} else {
899+
VolumeDetailVO iopsLimit = _volDetailDao.findDetail(volumeId, Volume.IOPS_LIMIT);
900+
if (iopsLimit != null) {
901+
_volDetailDao.remove(iopsLimit.getId());
902+
}
903+
}
904+
if (!volumeDetailsVO.isEmpty()) {
905+
_volDetailDao.saveDetails(volumeDetailsVO);
906+
}
907+
}
908+
894909
private DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
895910
Account owner, long deviceId, String configurationId) {
896911
assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template.";

engine/schema/src/main/java/com/cloud/storage/VolumeDetailVO.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,7 @@ public boolean isDisplay() {
8080
return display;
8181
}
8282

83+
public void setValue(String value) {
84+
this.value = value;
85+
}
8386
}

plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import javax.inject.Inject;
2424

25+
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
2526
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
2627
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
2728
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
@@ -38,6 +39,8 @@
3839
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
3940
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
4041
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
42+
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
43+
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
4144
import org.apache.cloudstack.storage.RemoteHostEndPoint;
4245
import org.apache.cloudstack.storage.command.CommandResult;
4346
import org.apache.cloudstack.storage.command.CopyCommand;
@@ -127,11 +130,15 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
127130
@Inject
128131
private ConfigurationDao configDao;
129132
@Inject
133+
private DiskOfferingDetailsDao diskOfferingDetailsDao;
134+
@Inject
130135
private HostDao hostDao;
131136
@Inject
132137
private VMInstanceDao vmInstanceDao;
133138
@Inject
134139
private VolumeService volumeService;
140+
@Inject
141+
private VolumeOrchestrationService volumeMgr;
135142

136143
public ScaleIOPrimaryDataStoreDriver() {
137144

@@ -141,40 +148,47 @@ public ScaleIOGatewayClient getScaleIOClient(final Long storagePoolId) throws Ex
141148
return ScaleIOGatewayClientConnectionPool.getInstance().getClient(storagePoolId, storagePoolDetailsDao);
142149
}
143150

151+
private boolean setVolumeLimitsOnSDC(VolumeVO volume, Host host, DataStore dataStore, Long iopsLimit, Long bandwidthLimitInKbps) throws Exception {
152+
final String sdcId = getConnectedSdc(dataStore.getId(), host.getId());
153+
if (StringUtils.isBlank(sdcId)) {
154+
alertHostSdcDisconnection(host);
155+
throw new CloudRuntimeException("Unable to grant access to volume: " + volume.getId() + ", no Sdc connected with host ip: " + host.getPrivateIpAddress());
156+
}
157+
158+
final ScaleIOGatewayClient client = getScaleIOClient(dataStore.getId());
159+
return client.mapVolumeToSdcWithLimits(ScaleIOUtil.getVolumePath(volume.getPath()), sdcId, iopsLimit, bandwidthLimitInKbps);
160+
}
161+
162+
private boolean setVolumeLimitsFromDetails(VolumeVO volume, Host host, DataStore dataStore) throws Exception {
163+
Long bandwidthLimitInKbps = 0L; // Unlimited
164+
// Check Bandwidth Limit parameter in volume details
165+
final VolumeDetailVO bandwidthVolumeDetail = volumeDetailsDao.findDetail(volume.getId(), Volume.BANDWIDTH_LIMIT_IN_MBPS);
166+
if (bandwidthVolumeDetail != null && bandwidthVolumeDetail.getValue() != null) {
167+
bandwidthLimitInKbps = Long.parseLong(bandwidthVolumeDetail.getValue()) * 1024;
168+
}
169+
170+
Long iopsLimit = 0L; // Unlimited
171+
// Check IOPS Limit parameter in volume details, else try MaxIOPS
172+
final VolumeDetailVO iopsVolumeDetail = volumeDetailsDao.findDetail(volume.getId(), Volume.IOPS_LIMIT);
173+
if (iopsVolumeDetail != null && iopsVolumeDetail.getValue() != null) {
174+
iopsLimit = Long.parseLong(iopsVolumeDetail.getValue());
175+
} else if (volume.getMaxIops() != null) {
176+
iopsLimit = volume.getMaxIops();
177+
}
178+
if (iopsLimit > 0 && iopsLimit < ScaleIOUtil.MINIMUM_ALLOWED_IOPS_LIMIT) {
179+
iopsLimit = ScaleIOUtil.MINIMUM_ALLOWED_IOPS_LIMIT;
180+
}
181+
182+
return setVolumeLimitsOnSDC(volume, host, dataStore, iopsLimit, bandwidthLimitInKbps);
183+
}
184+
144185
@Override
145186
public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore) {
146187
try {
147188
if (DataObjectType.VOLUME.equals(dataObject.getType())) {
148189
final VolumeVO volume = volumeDao.findById(dataObject.getId());
149190
LOGGER.debug("Granting access for PowerFlex volume: " + volume.getPath());
150-
151-
Long bandwidthLimitInKbps = Long.valueOf(0); // Unlimited
152-
// Check Bandwidht Limit parameter in volume details
153-
final VolumeDetailVO bandwidthVolumeDetail = volumeDetailsDao.findDetail(volume.getId(), Volume.BANDWIDTH_LIMIT_IN_MBPS);
154-
if (bandwidthVolumeDetail != null && bandwidthVolumeDetail.getValue() != null) {
155-
bandwidthLimitInKbps = Long.parseLong(bandwidthVolumeDetail.getValue()) * 1024;
156-
}
157-
158-
Long iopsLimit = Long.valueOf(0); // Unlimited
159-
// Check IOPS Limit parameter in volume details, else try MaxIOPS
160-
final VolumeDetailVO iopsVolumeDetail = volumeDetailsDao.findDetail(volume.getId(), Volume.IOPS_LIMIT);
161-
if (iopsVolumeDetail != null && iopsVolumeDetail.getValue() != null) {
162-
iopsLimit = Long.parseLong(iopsVolumeDetail.getValue());
163-
} else if (volume.getMaxIops() != null) {
164-
iopsLimit = volume.getMaxIops();
165-
}
166-
if (iopsLimit > 0 && iopsLimit < ScaleIOUtil.MINIMUM_ALLOWED_IOPS_LIMIT) {
167-
iopsLimit = ScaleIOUtil.MINIMUM_ALLOWED_IOPS_LIMIT;
168-
}
169-
170-
final String sdcId = getConnectedSdc(dataStore.getId(), host.getId());
171-
if (StringUtils.isBlank(sdcId)) {
172-
alertHostSdcDisconnection(host);
173-
throw new CloudRuntimeException("Unable to grant access to volume: " + dataObject.getId() + ", no Sdc connected with host ip: " + host.getPrivateIpAddress());
174-
}
175-
176-
final ScaleIOGatewayClient client = getScaleIOClient(dataStore.getId());
177-
return client.mapVolumeToSdcWithLimits(ScaleIOUtil.getVolumePath(volume.getPath()), sdcId, iopsLimit, bandwidthLimitInKbps);
191+
return setVolumeLimitsFromDetails(volume, host, dataStore);
178192
} else if (DataObjectType.TEMPLATE.equals(dataObject.getType())) {
179193
final VMTemplateStoragePoolVO templatePoolRef = vmTemplatePoolDao.findByPoolTemplate(dataStore.getId(), dataObject.getId(), null);
180194
LOGGER.debug("Granting access for PowerFlex template volume: " + templatePoolRef.getInstallPath());
@@ -791,7 +805,15 @@ private Answer copyTemplateToVolume(DataObject srcData, DataObject destData, Hos
791805
LOGGER.error(errorMsg);
792806
answer = new Answer(cmd, false, errorMsg);
793807
} else {
794-
answer = ep.sendMessage(cmd);
808+
VolumeVO volume = volumeDao.findById(destData.getId());
809+
Host host = destHost != null ? destHost : hostDao.findById(ep.getId());
810+
try {
811+
setVolumeLimitsOnSDC(volume, host, destData.getDataStore(), 0L, 0L);
812+
answer = ep.sendMessage(cmd);
813+
} catch (Exception e) {
814+
LOGGER.error("Failed to copy template to volume due to: " + e.getMessage(), e);
815+
answer = new Answer(cmd, false, e.getMessage());
816+
}
795817
}
796818

797819
return answer;
@@ -1181,7 +1203,7 @@ private void resizeVolume(VolumeInfo volumeInfo) {
11811203
ResizeVolumePayload payload = (ResizeVolumePayload)volumeInfo.getpayload();
11821204
long newSizeInBytes = payload.newSize != null ? payload.newSize : volumeInfo.getSize();
11831205
// Only increase size is allowed and size should be specified in granularity of 8 GB
1184-
if (newSizeInBytes <= volumeInfo.getSize()) {
1206+
if (newSizeInBytes < volumeInfo.getSize()) {
11851207
throw new CloudRuntimeException("Only increase size is allowed for volume: " + volumeInfo.getName());
11861208
}
11871209

@@ -1210,6 +1232,20 @@ private void resizeVolume(VolumeInfo volumeInfo) {
12101232
}
12111233
}
12121234

1235+
Long newMaxIops = payload.newMaxIops != null ? payload.newMaxIops : volumeInfo.getMaxIops();
1236+
long newBandwidthLimit = 0L;
1237+
Long newDiskOfferingId = payload.newDiskOfferingId != null ? payload.newDiskOfferingId : volumeInfo.getDiskOfferingId();
1238+
if (newDiskOfferingId != null) {
1239+
DiskOfferingDetailVO bandwidthLimitDetail = diskOfferingDetailsDao.findDetail(newDiskOfferingId, Volume.BANDWIDTH_LIMIT_IN_MBPS);
1240+
if (bandwidthLimitDetail != null) {
1241+
newBandwidthLimit = Long.parseLong(bandwidthLimitDetail.getValue()) * 1024;
1242+
}
1243+
DiskOfferingDetailVO iopsLimitDetail = diskOfferingDetailsDao.findDetail(newDiskOfferingId, Volume.IOPS_LIMIT);
1244+
if (iopsLimitDetail != null) {
1245+
newMaxIops = Long.parseLong(iopsLimitDetail.getValue());
1246+
}
1247+
}
1248+
12131249
if (volumeInfo.getFormat().equals(Storage.ImageFormat.QCOW2) || attachedRunning) {
12141250
LOGGER.debug("Volume needs to be resized at the hypervisor host");
12151251

@@ -1229,9 +1265,8 @@ private void resizeVolume(VolumeInfo volumeInfo) {
12291265
volumeInfo.getPassphrase(), volumeInfo.getEncryptFormat());
12301266

12311267
try {
1232-
if (!attachedRunning) {
1233-
grantAccess(volumeInfo, ep, volumeInfo.getDataStore());
1234-
}
1268+
VolumeVO volume = volumeDao.findById(volumeInfo.getId());
1269+
setVolumeLimitsOnSDC(volume, host, volumeInfo.getDataStore(), newMaxIops != null ? newMaxIops : 0L, newBandwidthLimit);
12351270
Answer answer = ep.sendMessage(resizeVolumeCommand);
12361271

12371272
if (!answer.getResult() && volumeInfo.getFormat().equals(Storage.ImageFormat.QCOW2)) {
@@ -1253,14 +1288,23 @@ private void resizeVolume(VolumeInfo volumeInfo) {
12531288
VolumeVO volume = volumeDao.findById(volumeInfo.getId());
12541289
long oldVolumeSize = volume.getSize();
12551290
volume.setSize(scaleIOVolume.getSizeInKb() * 1024);
1291+
if (payload.newMinIops != null) {
1292+
volume.setMinIops(payload.newMinIops);
1293+
}
1294+
if (payload.newMaxIops != null) {
1295+
volume.setMaxIops(payload.newMaxIops);
1296+
}
12561297
volumeDao.update(volume.getId(), volume);
1298+
if (payload.newDiskOfferingId != null) {
1299+
volumeMgr.saveVolumeDetails(payload.newDiskOfferingId, volume.getId());
1300+
}
12571301

12581302
long capacityBytes = storagePool.getCapacityBytes();
12591303
long usedBytes = storagePool.getUsedBytes();
12601304

12611305
long newVolumeSize = volume.getSize();
12621306
usedBytes += newVolumeSize - oldVolumeSize;
1263-
storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes);
1307+
storagePool.setUsedBytes(Math.min(usedBytes, capacityBytes));
12641308
storagePoolDao.update(storagePoolId, storagePool);
12651309
} catch (Exception e) {
12661310
String errMsg = "Unable to resize PowerFlex volume: " + volumeInfo.getId() + " due to " + e.getMessage();

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class ResizeVolumePayload {
2121
public final Long newSize;
2222
public final Long newMinIops;
2323
public final Long newMaxIops;
24+
public Long newDiskOfferingId;
2425
public final Integer newHypervisorSnapshotReserve;
2526
public final boolean shrinkOk;
2627
public final String instanceName;
@@ -37,5 +38,12 @@ public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, Integ
3738
this.instanceName = instanceName;
3839
this.hosts = hosts;
3940
this.isManaged = isManaged;
41+
this.newDiskOfferingId = null;
42+
}
43+
44+
public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, Long newDiskOfferingId, Integer newHypervisorSnapshotReserve, boolean shrinkOk,
45+
String instanceName, long[] hosts, boolean isManaged) {
46+
this(newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, shrinkOk, instanceName, hosts, isManaged);
47+
this.newDiskOfferingId = newDiskOfferingId;
4048
}
4149
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1475,7 +1475,7 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n
14751475
}
14761476
}
14771477

1478-
ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, shrinkOk, instanceName, hosts, isManaged);
1478+
ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, newDiskOfferingId, newHypervisorSnapshotReserve, shrinkOk, instanceName, hosts, isManaged);
14791479

14801480
try {
14811481
VolumeInfo vol = volFactory.getVolume(volume.getId());
@@ -1514,6 +1514,15 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n
15141514

15151515
if (newDiskOfferingId != null) {
15161516
volume.setDiskOfferingId(newDiskOfferingId);
1517+
_volumeMgr.saveVolumeDetails(newDiskOfferingId, volume.getId());
1518+
}
1519+
1520+
if (newMinIops != null) {
1521+
volume.setMinIops(newMinIops);
1522+
}
1523+
1524+
if (newMaxIops != null) {
1525+
volume.setMaxIops(newMaxIops);
15171526
}
15181527

15191528
// Update size if volume has same size as before, else it is already updated
@@ -2033,6 +2042,7 @@ private Volume changeDiskOfferingForVolumeInternal(VolumeVO volume, Long newDisk
20332042

20342043
if (newDiskOffering != null) {
20352044
volume.setDiskOfferingId(newDiskOfferingId);
2045+
_volumeMgr.saveVolumeDetails(newDiskOfferingId, volume.getId());
20362046
}
20372047

20382048
_volsDao.update(volume.getId(), volume);

0 commit comments

Comments
 (0)