Skip to content

Commit 97a64ab

Browse files
committed
resizeVolume: support automigrate
1 parent a84e65e commit 97a64ab

File tree

4 files changed

+73
-12
lines changed

4 files changed

+73
-12
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ public class ResizeVolumeCmd extends BaseAsyncCmd implements UserCmd {
7373
description = "new disk offering id")
7474
private Long newDiskOfferingId;
7575

76+
@Parameter(name = ApiConstants.AUTO_MIGRATE, type = CommandType.BOOLEAN, required = false,
77+
description = "Flag for automatic migration of the volume whenever migration is required to apply the new size")
78+
private Boolean autoMigrate;
79+
7680
/////////////////////////////////////////////////////
7781
/////////////////// Accessors ///////////////////////
7882
/////////////////////////////////////////////////////
@@ -129,6 +133,10 @@ public Long getNewDiskOfferingId() {
129133
return newDiskOfferingId;
130134
}
131135

136+
public boolean getAutoMigrate() {
137+
return autoMigrate == null ? false : autoMigrate;
138+
}
139+
132140
/////////////////////////////////////////////////////
133141
/////////////// API Implementation///////////////////
134142
/////////////////////////////////////////////////////

engine/components-api/src/main/java/com/cloud/storage/StorageManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public interface StorageManager extends StorageService {
211211

212212
ConfigKey<Boolean> AllowVolumeReSizeBeyongAllocation = new ConfigKey<Boolean>("Advanced", Boolean.class, "volume.resize.allowed.beyond.allocation", "false",
213213
"Determines whether volume size can exceed the pool capacity allocation disable threshold (pool.storage.allocated.capacity.disablethreshold) when resize a volume",
214-
true, ConfigKey.Scope.StoragePool);
214+
true, ConfigKey.Scope.Zone);
215215

216216
/**
217217
* should we execute in sequence not involving any storages?

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3101,7 +3101,7 @@ public boolean storagePoolHasEnoughSpaceForResize(StoragePool pool, long current
31013101
} else {
31023102
final StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId());
31033103
final long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null);
3104-
return checkPoolforSpace(pool, allocatedSizeWithTemplate, totalAskingSize);
3104+
return checkPoolforSpace(pool, allocatedSizeWithTemplate, totalAskingSize, true);
31053105
}
31063106
}
31073107

@@ -3164,6 +3164,10 @@ public boolean isStoragePoolCompliantWithStoragePolicy(List<Pair<Volume, DiskPro
31643164
}
31653165

31663166
protected boolean checkPoolforSpace(StoragePool pool, long allocatedSizeWithTemplate, long totalAskingSize) {
3167+
return checkPoolforSpace(pool, allocatedSizeWithTemplate, totalAskingSize, false);
3168+
}
3169+
3170+
protected boolean checkPoolforSpace(StoragePool pool, long allocatedSizeWithTemplate, long totalAskingSize, boolean forVolumeResize) {
31673171
// allocated space includes templates
31683172
StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId());
31693173

@@ -3185,15 +3189,13 @@ protected boolean checkPoolforSpace(StoragePool pool, long allocatedSizeWithTemp
31853189
logger.debug("Total capacity of the pool " + poolVO.getName() + " with ID " + pool.getId() + " is " + toHumanReadableSize(totalOverProvCapacity));
31863190

31873191
double storageAllocatedThreshold = CapacityManager.StorageAllocatedCapacityDisableThreshold.valueIn(pool.getDataCenterId());
3188-
System.out.println("Wei storageAllocatedThreshold = " + storageAllocatedThreshold);
31893192

31903193
if (logger.isDebugEnabled()) {
31913194
logger.debug("Checking pool: " + pool.getId() + " for storage allocation , maxSize : " + toHumanReadableSize(totalOverProvCapacity) + ", totalAllocatedSize : " + toHumanReadableSize(allocatedSizeWithTemplate)
31923195
+ ", askingSize : " + toHumanReadableSize(totalAskingSize) + ", allocated disable threshold: " + storageAllocatedThreshold);
31933196
}
31943197

31953198
double usedPercentage = (allocatedSizeWithTemplate + totalAskingSize) / (double)(totalOverProvCapacity);
3196-
System.out.println("Wei usedPercentage = " + usedPercentage);
31973199

31983200
if (usedPercentage > storageAllocatedThreshold) {
31993201
if (logger.isDebugEnabled()) {

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

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep
10931093
Long newMaxIops = cmd.getMaxIops();
10941094
Integer newHypervisorSnapshotReserve = null;
10951095
boolean shrinkOk = cmd.isShrinkOk();
1096+
boolean autoMigrateVolume = cmd.getAutoMigrate();
10961097

10971098
VolumeVO volume = _volsDao.findById(cmd.getEntityId());
10981099
if (volume == null) {
@@ -1154,8 +1155,6 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep
11541155
newSize = volume.getSize();
11551156
}
11561157

1157-
newMinIops = cmd.getMinIops();
1158-
11591158
if (newMinIops != null) {
11601159
if (!volume.getVolumeType().equals(Volume.Type.ROOT) && (diskOffering.isCustomizedIops() == null || !diskOffering.isCustomizedIops())) {
11611160
throw new InvalidParameterValueException("The current disk offering does not support customization of the 'Min IOPS' parameter.");
@@ -1165,8 +1164,6 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep
11651164
newMinIops = volume.getMinIops();
11661165
}
11671166

1168-
newMaxIops = cmd.getMaxIops();
1169-
11701167
if (newMaxIops != null) {
11711168
if (!volume.getVolumeType().equals(Volume.Type.ROOT) && (diskOffering.isCustomizedIops() == null || !diskOffering.isCustomizedIops())) {
11721169
throw new InvalidParameterValueException("The current disk offering does not support customization of the 'Max IOPS' parameter.");
@@ -1288,6 +1285,53 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep
12881285
return volume;
12891286
}
12901287

1288+
Long newDiskOfferingId = newDiskOffering != null ? newDiskOffering.getId() : diskOffering.getId();
1289+
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOfferingId, currentSize, newMinIops, newMaxIops, true, false);
1290+
List<? extends StoragePool> suitableStoragePools = poolsPair.second();
1291+
1292+
boolean volumeMigrateRequired = false;
1293+
StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
1294+
if (!storageMgr.storagePoolHasEnoughSpaceForResize(storagePool, currentSize, newSize)) {
1295+
volumeMigrateRequired = true;
1296+
if (!autoMigrateVolume) {
1297+
throw new CloudRuntimeException(String.format("Failed to resize volume %s since the storage pool does not have enough space to resize volume %s, automigrate is set to false but volume needs to migrated.", volume.getUuid(), volume.getName()));
1298+
}
1299+
}
1300+
1301+
boolean volumeResizeRequired = false;
1302+
if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) {
1303+
volumeResizeRequired = true;
1304+
}
1305+
if (!volumeMigrateRequired && !volumeResizeRequired && newDiskOffering != null) {
1306+
_volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId());
1307+
volume = _volsDao.findById(volume.getId());
1308+
updateStorageWithTheNewDiskOffering(volume, newDiskOffering);
1309+
1310+
return volume;
1311+
}
1312+
1313+
if (volumeMigrateRequired) {
1314+
if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second())) {
1315+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resize operation failed for volume ID: %s as no suitable pool(s) found for migrating to support new disk offering or new size", volume.getUuid()));
1316+
}
1317+
final Long newSizeFinal = newSize;
1318+
List<? extends StoragePool> suitableStoragePoolsWithEnoughSpace = suitableStoragePools.stream().filter(pool -> storageMgr.storagePoolHasEnoughSpaceForResize(pool, 0L, newSizeFinal)).collect(Collectors.toList());
1319+
if (CollectionUtils.isEmpty(suitableStoragePoolsWithEnoughSpace)) {
1320+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resize operation failed for volume ID: %s as no suitable pool(s) with enough space found for volume migration.", volume.getUuid()));
1321+
}
1322+
Collections.shuffle(suitableStoragePoolsWithEnoughSpace);
1323+
MigrateVolumeCmd migrateVolumeCmd = new MigrateVolumeCmd(volume.getId(), suitableStoragePoolsWithEnoughSpace.get(0).getId(), newDiskOfferingId, true);
1324+
try {
1325+
Volume result = migrateVolume(migrateVolumeCmd);
1326+
volume = (result != null) ? _volsDao.findById(result.getId()) : null;
1327+
if (volume == null) {
1328+
throw new CloudRuntimeException(String.format("Volume resize operation failed for volume ID: %s migration failed to storage pool %s", volume.getUuid(), suitableStoragePools.get(0).getId()));
1329+
}
1330+
} catch (Exception e) {
1331+
throw new CloudRuntimeException(String.format("Volume resize operation failed for volume ID: %s migration failed to storage pool %s due to %s", volume.getUuid(), suitableStoragePools.get(0).getId(), e.getMessage()));
1332+
}
1333+
}
1334+
12911335
UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
12921336

12931337
if (userVm != null) {
@@ -1973,6 +2017,7 @@ public Outcome<Pair> checkAndRepairVolumeThroughJobQueue(final Long vmId, final
19732017
public Volume changeDiskOfferingForVolume(ChangeOfferingForVolumeCmd cmd) throws ResourceAllocationException {
19742018
Long newSize = cmd.getSize();
19752019
Long newMinIops = cmd.getMinIops();
2020+
19762021
Long newMaxIops = cmd.getMaxIops();
19772022
Long newDiskOfferingId = cmd.getNewDiskOfferingId();
19782023
boolean shrinkOk = cmd.isShrinkOk();
@@ -2055,7 +2100,7 @@ public Volume changeDiskOfferingForVolumeInternal(Long volumeId, Long newDiskOff
20552100

20562101
StoragePoolVO existingStoragePool = _storagePoolDao.findById(volume.getPoolId());
20572102

2058-
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOffering.getId(), newSize, newMinIops, newMaxIops, true, false);
2103+
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOffering.getId(), currentSize, newMinIops, newMaxIops, true, false);
20592104
List<? extends StoragePool> suitableStoragePools = poolsPair.second();
20602105

20612106
if (!suitableStoragePools.stream().anyMatch(p -> (p.getId() == existingStoragePool.getId()))) {
@@ -2077,10 +2122,16 @@ public Volume changeDiskOfferingForVolumeInternal(Long volumeId, Long newDiskOff
20772122
if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second())) {
20782123
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume change offering operation failed for volume ID: %s as no suitable pool(s) found for migrating to support new disk offering", volume.getUuid()));
20792124
}
2080-
Collections.shuffle(suitableStoragePools);
2081-
MigrateVolumeCmd migrateVolumeCmd = new MigrateVolumeCmd(volume.getId(), suitableStoragePools.get(0).getId(), newDiskOffering.getId(), true);
2125+
final Long newSizeFinal = newSize;
2126+
List<? extends StoragePool> suitableStoragePoolsWithEnoughSpace = suitableStoragePools.stream().filter(pool -> storageMgr.storagePoolHasEnoughSpaceForResize(pool, 0L, newSizeFinal)).collect(Collectors.toList());
2127+
if (CollectionUtils.isEmpty(suitableStoragePoolsWithEnoughSpace)) {
2128+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume change offering operation failed for volume ID: %s as no suitable pool(s) with enough space found for volume migration.", volume.getUuid()));
2129+
}
2130+
Collections.shuffle(suitableStoragePoolsWithEnoughSpace);
2131+
MigrateVolumeCmd migrateVolumeCmd = new MigrateVolumeCmd(volume.getId(), suitableStoragePoolsWithEnoughSpace.get(0).getId(), newDiskOffering.getId(), true);
20822132
try {
2083-
volume = (VolumeVO) migrateVolume(migrateVolumeCmd);
2133+
Volume result = migrateVolume(migrateVolumeCmd);
2134+
volume = (result != null) ? _volsDao.findById(result.getId()) : null;
20842135
if (volume == null) {
20852136
throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume ID: %s migration failed to storage pool %s", volume.getUuid(), suitableStoragePools.get(0).getId()));
20862137
}

0 commit comments

Comments
 (0)