Skip to content

Commit b080eaf

Browse files
author
Mike Tutkowski
committed
Updates to the way resizing a volume works
1 parent ef28fd3 commit b080eaf

10 files changed

Lines changed: 319 additions & 85 deletions

File tree

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@ public class ResizeVolumeCmd extends BaseAsyncCmd {
5555
@Parameter(name = ApiConstants.ID, entityType = VolumeResponse.class, required = true, type = CommandType.UUID, description = "the ID of the disk volume")
5656
private Long id;
5757

58-
@Parameter(name = ApiConstants.SIZE, type = CommandType.LONG, required = false, description = "New volume size in G")
58+
@Parameter(name = ApiConstants.MIN_IOPS, type = CommandType.LONG, required = false, description = "New minimum number of IOPS")
59+
private Long minIops;
60+
61+
@Parameter(name = ApiConstants.MAX_IOPS, type = CommandType.LONG, required = false, description = "New maximum number of IOPS")
62+
private Long maxIops;
63+
64+
@Parameter(name = ApiConstants.SIZE, type = CommandType.LONG, required = false, description = "New volume size in GB")
5965
private Long size;
6066

6167
@Parameter(name = ApiConstants.SHRINK_OK, type = CommandType.BOOLEAN, required = false, description = "Verify OK to Shrink")
@@ -81,6 +87,14 @@ public Long getId() {
8187
return getEntityId();
8288
}
8389

90+
public Long getMinIops() {
91+
return minIops;
92+
}
93+
94+
public Long getMaxIops() {
95+
return maxIops;
96+
}
97+
8498
public Long getSize() {
8599
return size;
86100
}

engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume
9696

9797
AsyncCallFuture<VolumeApiResult> resize(VolumeInfo volume);
9898

99+
void resizeVolumeOnHypervisor(long volumeId, long newSize, long destHostId, String instanceName);
100+
99101
void handleVolumeSync(DataStore store);
100102

101103
SnapshotInfo takeSnapshot(VolumeInfo volume);

engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
5252
import org.apache.cloudstack.framework.async.AsyncRpcContext;
5353
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
54+
import org.apache.cloudstack.storage.RemoteHostEndPoint;
5455
import org.apache.cloudstack.storage.command.CommandResult;
5556
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
5657
import org.apache.cloudstack.storage.command.DeleteCommand;
@@ -65,6 +66,8 @@
6566
import com.cloud.agent.api.Answer;
6667
import com.cloud.agent.api.storage.ListVolumeAnswer;
6768
import com.cloud.agent.api.storage.ListVolumeCommand;
69+
import com.cloud.agent.api.storage.ResizeVolumeCommand;
70+
import com.cloud.agent.api.to.StorageFilerTO;
6871
import com.cloud.agent.api.to.VirtualMachineTO;
6972
import com.cloud.alert.AlertManager;
7073
import com.cloud.configuration.Config;
@@ -1280,6 +1283,33 @@ public AsyncCallFuture<VolumeApiResult> resize(VolumeInfo volume) {
12801283
return future;
12811284
}
12821285

1286+
@Override
1287+
public void resizeVolumeOnHypervisor(long volumeId, long newSize, long destHostId, String instanceName) {
1288+
final String errMsg = "Resize command failed";
1289+
1290+
try {
1291+
Answer answer = null;
1292+
Host destHost = _hostDao.findById(destHostId);
1293+
EndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(destHost);
1294+
1295+
if (ep != null) {
1296+
VolumeVO volume = _volumeDao.findById(volumeId);
1297+
PrimaryDataStore primaryDataStore = this.dataStoreMgr.getPrimaryDataStore(volume.getPoolId());
1298+
ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(primaryDataStore), volume.getSize(), newSize, true, instanceName);
1299+
1300+
answer = ep.sendMessage(resizeCmd);
1301+
} else {
1302+
throw new CloudRuntimeException("Could not find a remote endpoint to send command to. Check if host or SSVM is down.");
1303+
}
1304+
1305+
if (answer == null || !answer.getResult()) {
1306+
throw new CloudRuntimeException(answer != null ? answer.getDetails() : errMsg);
1307+
}
1308+
} catch (Exception e) {
1309+
throw new CloudRuntimeException(errMsg, e);
1310+
}
1311+
}
1312+
12831313
protected Void resizeVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback, CreateVolumeContext<VolumeApiResult> context) {
12841314
CreateCmdResult result = callback.getResult();
12851315
AsyncCallFuture<VolumeApiResult> future = context.future;

plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@
4242
import com.cloud.agent.api.to.DataObjectType;
4343
import com.cloud.agent.api.to.DataStoreTO;
4444
import com.cloud.agent.api.to.DataTO;
45+
import com.cloud.capacity.CapacityManager;
4546
import com.cloud.dc.ClusterDetailsVO;
4647
import com.cloud.dc.ClusterDetailsDao;
4748
import com.cloud.dc.dao.DataCenterDao;
4849
import com.cloud.host.Host;
4950
import com.cloud.host.HostVO;
5051
import com.cloud.host.dao.HostDao;
5152
import com.cloud.storage.Storage.StoragePoolType;
53+
import com.cloud.storage.ResizeVolumePayload;
5254
import com.cloud.storage.StoragePool;
5355
import com.cloud.storage.Volume;
5456
import com.cloud.storage.VolumeVO;
@@ -57,10 +59,12 @@
5759
import com.cloud.user.AccountDetailsDao;
5860
import com.cloud.user.AccountVO;
5961
import com.cloud.user.dao.AccountDao;
62+
import com.cloud.utils.exception.CloudRuntimeException;
6063

6164
public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
6265
@Inject private AccountDao _accountDao;
6366
@Inject private AccountDetailsDao _accountDetailsDao;
67+
@Inject private CapacityManager _capacityMgr;
6468
@Inject private ClusterDetailsDao _clusterDetailsDao;
6569
@Inject private DataCenterDao _zoneDao;
6670
@Inject private HostDao _hostDao;
@@ -400,8 +404,58 @@ public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<Comman
400404
}
401405

402406
@Override
403-
public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
404-
throw new UnsupportedOperationException();
407+
public void resize(DataObject dataObject, AsyncCompletionCallback<CreateCmdResult> callback) {
408+
String iqn = null;
409+
String errMsg = null;
410+
411+
if (dataObject.getType() == DataObjectType.VOLUME) {
412+
VolumeInfo volumeInfo = (VolumeInfo)dataObject;
413+
iqn = volumeInfo.get_iScsiName();
414+
long storagePoolId = volumeInfo.getPoolId();
415+
long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
416+
ResizeVolumePayload payload = (ResizeVolumePayload)volumeInfo.getpayload();
417+
418+
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
419+
SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
420+
421+
verifySufficientIopsForStoragePool(storagePoolId, volumeInfo.getId(), payload.newMinIops);
422+
423+
SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfVolume.getTotalSize(), payload.newMinIops, payload.newMaxIops,
424+
getDefaultBurstIops(storagePoolId, payload.newMaxIops));
425+
426+
VolumeVO volume = _volumeDao.findById(sfVolumeId);
427+
428+
volume.setMinIops(payload.newMinIops);
429+
volume.setMaxIops(payload.newMaxIops);
430+
431+
_volumeDao.update(volume.getId(), volume);
432+
} else {
433+
errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to resize";
434+
}
435+
436+
CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg));
437+
438+
result.setResult(errMsg);
439+
440+
callback.complete(result);
441+
}
442+
443+
private void verifySufficientIopsForStoragePool(long storagePoolId, long volumeId, long newMinIops) {
444+
StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
445+
VolumeVO volume = _volumeDao.findById(volumeId);
446+
447+
long currentMinIops = volume.getMinIops();
448+
long diffInMinIops = newMinIops - currentMinIops;
449+
450+
// if the desire is for more IOPS
451+
if (diffInMinIops > 0) {
452+
long usedIops = _capacityMgr.getUsedIops(storagePool);
453+
long capacityIops = storagePool.getCapacityIops();
454+
455+
if (usedIops + diffInMinIops > capacityIops) {
456+
throw new CloudRuntimeException("Insufficient number of IOPS available in this storage pool");
457+
}
458+
}
405459
}
406460

407461
@Override

plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle {
5454
private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreLifeCycle.class);
5555

56-
@Inject CapacityManager _capacityMgr;
56+
@Inject private CapacityManager _capacityMgr;
5757
@Inject private DataCenterDao zoneDao;
5858
@Inject private PrimaryDataStoreDao storagePoolDao;
5959
@Inject private PrimaryDataStoreHelper dataStoreHelper;

server/src/com/cloud/network/NetworkServiceImpl.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
import com.cloud.utils.Journal;
159159
import com.cloud.utils.NumbersUtil;
160160
import com.cloud.utils.Pair;
161+
import com.cloud.utils.StringUtils;
161162
import com.cloud.utils.component.ManagerBase;
162163
import com.cloud.utils.db.DB;
163164
import com.cloud.utils.db.EntityManager;
@@ -2403,7 +2404,8 @@ protected boolean canUpgrade(Network network, long oldNetworkOfferingId, long ne
24032404
s_logger.debug("New network offering id=" + newNetworkOfferingId + " has tags and old network offering id=" + oldNetworkOfferingId + " doesn't, can't upgrade");
24042405
return false;
24052406
}
2406-
if (!oldNetworkOffering.getTags().equalsIgnoreCase(newNetworkOffering.getTags())) {
2407+
2408+
if (!StringUtils.areTagsEqual(oldNetworkOffering.getTags(), newNetworkOffering.getTags())) {
24072409
s_logger.debug("Network offerings " + newNetworkOffering.getUuid() + " and " + oldNetworkOffering.getUuid() + " have different tags, can't upgrade");
24082410
return false;
24092411
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@
1919

2020
public class ResizeVolumePayload {
2121
public final Long newSize;
22+
public final Long newMinIops;
23+
public final Long newMaxIops;
2224
public final boolean shrinkOk;
2325
public final String instanceName;
2426
public final long[] hosts;
2527

26-
public ResizeVolumePayload(Long newSize, boolean shrinkOk, String instanceName, long[] hosts) {
28+
public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, boolean shrinkOk, String instanceName, long[] hosts) {
2729
this.newSize = newSize;
30+
this.newMinIops = newMinIops;
31+
this.newMaxIops = newMaxIops;
2832
this.shrinkOk = shrinkOk;
2933
this.instanceName = instanceName;
3034
this.hosts = hosts;

server/src/com/cloud/storage/VmWorkResizeVolume.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,21 @@ public class VmWorkResizeVolume extends VmWork {
2424
private long volumeId;
2525
private long currentSize;
2626
private long newSize;
27+
private Long newMinIops;
28+
private Long newMaxIops;
2729
private Long newServiceOfferingId;
2830
private boolean shrinkOk;
2931

3032
public VmWorkResizeVolume(long userId, long accountId, long vmId, String handlerName,
31-
long volumeId, long currentSize, long newSize, Long newServiceOfferingId, boolean shrinkOk) {
33+
long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, Long newServiceOfferingId, boolean shrinkOk) {
3234

3335
super(userId, accountId, vmId, handlerName);
3436

3537
this.volumeId = volumeId;
3638
this.currentSize = currentSize;
3739
this.newSize = newSize;
40+
this.newMinIops = newMinIops;
41+
this.newMaxIops = newMaxIops;
3842
this.newServiceOfferingId = newServiceOfferingId;
3943
this.shrinkOk = shrinkOk;
4044
}
@@ -51,6 +55,14 @@ public long getNewSize() {
5155
return newSize;
5256
}
5357

58+
public long getNewMinIops() {
59+
return newMinIops;
60+
}
61+
62+
public long getNewMaxIops() {
63+
return newMaxIops;
64+
}
65+
5466
public Long getNewServiceOfferingId() {
5567
return newServiceOfferingId;
5668
}

0 commit comments

Comments
 (0)