Skip to content

Commit d6cbd77

Browse files
[CLOUDSTACK-10323] Allow changing disk offering during volume migration (apache#2486)
* [CLOUDSTACK-10323] Allow changing disk offering during volume migration This is a continuation of work developed on PR apache#2425 (CLOUDSTACK-10240), which provided root admins an override mechanism to move volumes between storage systems types (local/shared) even when the disk offering would not allow such operation. To complete the work, we will now provide a way for administrators to enter a new disk offering that can reflect the new placement of the volume. We will add an extra parameter to allow the root admin inform a new disk offering for the volume. Therefore, when the volume is being migrated, it will be possible to replace the disk offering to reflect the new placement of the volume. The API method will have the following parameters: * storageid (required) * volumeid (required) * livemigrate(optional) * newdiskofferingid (optional) – this is the new parameter The expected behavior is the following: * If “newdiskofferingid” is not provided the current behavior is maintained. Override mechanism will also keep working as we have seen so far. * If the “newdiskofferingid” is provided by the admin, we will execute the following checks ** new disk offering mode (local/shared) must match the target storage mode. If it does not match, an exception will be thrown and the operator will receive a message indicating the problem. ** we will check if the new disk offering tags match the target storage tags. If it does not match, an exception will be thrown and the operator will receive a message indicating the problem. ** check if the target storage has the capacity for the new volume. If it does not have enough space, then an exception is thrown and the operator will receive a message indicating the problem. ** check if the size of the volume is the same as the size of the new disk offering. If it is not the same, we will ALLOW the change of the service offering, and a warning message will be logged. We execute the change of the Disk offering as soon as the migration of the volume finishes. Therefore, if an error happens during the migration and the volume remains in the original storage system, the disk offering will keep reflecting this situation. * Code formatting * Adding a test to cover migration with new disk offering (#4) * Adding a test to cover migration with new disk offering * Update test_volumes.py * Update test_volumes.py * fix test_11_migrate_volume_and_change_offering * Fix typo in Java doc
1 parent 46bd94c commit d6cbd77

File tree

28 files changed

+788
-492
lines changed

28 files changed

+788
-492
lines changed

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public class ApiConstants {
8686
public static final String DEVICE_ID = "deviceid";
8787
public static final String DIRECT_DOWNLOAD = "directdownload";
8888
public static final String DISK_OFFERING_ID = "diskofferingid";
89+
public static final String NEW_DISK_OFFERING_ID = "newdiskofferingid";
8990
public static final String DISK_SIZE = "disksize";
9091
public static final String UTILIZATION = "utilization";
9192
public static final String DRIVER = "driver";

api/src/main/java/org/apache/cloudstack/api/command/admin/volume/MigrateVolumeCmdByAdmin.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,13 @@
2525

2626
import com.cloud.storage.Volume;
2727

28-
29-
@APICommand(name = "migrateVolume", description = "Migrate volume", responseObject = VolumeResponse.class, since = "3.0.0", responseView = ResponseView.Full, entityType = {Volume.class},
30-
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
28+
@APICommand(name = "migrateVolume", description = "Migrate volume", responseObject = VolumeResponse.class, since = "3.0.0", responseView = ResponseView.Full, entityType = {
29+
Volume.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
3130
public class MigrateVolumeCmdByAdmin extends MigrateVolumeCmd {
3231

33-
3432
@Override
35-
public void execute(){
36-
Volume result;
37-
38-
result = _volumeService.migrateVolume(this);
33+
public void execute() {
34+
Volume result = _volumeService.migrateVolume(this);
3935
if (result != null) {
4036
VolumeResponse response = _responseGenerator.createVolumeResponse(ResponseView.Full, result);
4137
response.setResponseName(getCommandName());

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

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,27 @@
3030
import com.cloud.storage.Volume;
3131
import com.cloud.user.Account;
3232

33-
@APICommand(name = "migrateVolume", description = "Migrate volume", responseObject = VolumeResponse.class, since = "3.0.0", responseView = ResponseView.Restricted, entityType = {Volume.class},
34-
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
33+
@APICommand(name = "migrateVolume", description = "Migrate volume", responseObject = VolumeResponse.class, since = "3.0.0", responseView = ResponseView.Restricted, entityType = {
34+
Volume.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
3535
public class MigrateVolumeCmd extends BaseAsyncCmd {
3636
private static final String s_name = "migratevolumeresponse";
3737

38-
/////////////////////////////////////////////////////
38+
/////////////////////////////////////////////////////
3939
//////////////// API parameters /////////////////////
4040
/////////////////////////////////////////////////////
4141

4242
@Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.UUID, entityType = VolumeResponse.class, required = true, description = "the ID of the volume")
4343
private Long volumeId;
4444

45-
@Parameter(name = ApiConstants.STORAGE_ID,
46-
type = CommandType.UUID,
47-
entityType = StoragePoolResponse.class,
48-
required = true,
49-
description = "destination storage pool ID to migrate the volume to")
45+
@Parameter(name = ApiConstants.STORAGE_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class, required = true, description = "destination storage pool ID to migrate the volume to")
5046
private Long storageId;
5147

52-
@Parameter(name = ApiConstants.LIVE_MIGRATE,
53-
type = CommandType.BOOLEAN,
54-
required = false,
55-
description = "if the volume should be live migrated when it is attached to a running vm")
48+
@Parameter(name = ApiConstants.LIVE_MIGRATE, type = CommandType.BOOLEAN, required = false, description = "if the volume should be live migrated when it is attached to a running vm")
5649
private Boolean liveMigrate;
5750

51+
@Parameter(name = ApiConstants.NEW_DISK_OFFERING_ID, type = CommandType.STRING, description = "The new disk offering ID that replaces the current one used by the volume. This new disk offering is used to better reflect the new storage where the volume is going to be migrated to.")
52+
private String newDiskOfferingUuid;
53+
5854
/////////////////////////////////////////////////////
5955
/////////////////// Accessors ///////////////////////
6056
/////////////////////////////////////////////////////
@@ -87,12 +83,12 @@ public String getCommandName() {
8783

8884
@Override
8985
public long getEntityOwnerId() {
90-
Volume volume = _entityMgr.findById(Volume.class, getVolumeId());
91-
if (volume != null) {
92-
return volume.getAccountId();
93-
}
86+
Volume volume = _entityMgr.findById(Volume.class, getVolumeId());
87+
if (volume != null) {
88+
return volume.getAccountId();
89+
}
9490

95-
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
91+
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
9692
}
9793

9894
@Override
@@ -105,6 +101,10 @@ public String getEventDescription() {
105101
return "Attempting to migrate volume Id: " + getVolumeId() + " to storage pool Id: " + getStoragePoolId();
106102
}
107103

104+
public String getNewDiskOfferingUuid() {
105+
return newDiskOfferingUuid;
106+
}
107+
108108
@Override
109109
public void execute() {
110110
Volume result;

engine/components-api/src/main/java/com/cloud/vm/VmWorkMigrateVolume.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ public class VmWorkMigrateVolume extends VmWork {
2222
private long volumeId;
2323
private long destPoolId;
2424
private boolean liveMigrate;
25+
private Long newDiskOfferingId;
2526

26-
public VmWorkMigrateVolume(long userId, long accountId, long vmId, String handlerName, long volumeId, long destPoolId, boolean liveMigrate) {
27+
public VmWorkMigrateVolume(long userId, long accountId, long vmId, String handlerName, long volumeId, long destPoolId, boolean liveMigrate, Long newDiskOfferingId) {
2728
super(userId, accountId, vmId, handlerName);
2829
this.volumeId = volumeId;
2930
this.destPoolId = destPoolId;
3031
this.liveMigrate = liveMigrate;
32+
this.newDiskOfferingId = newDiskOfferingId;
3133
}
3234

3335
public long getVolumeId() {
@@ -41,4 +43,8 @@ public long getDestPoolId() {
4143
public boolean isLiveMigrate() {
4244
return liveMigrate;
4345
}
46+
47+
public Long getNewDiskOfferingId() {
48+
return newDiskOfferingId;
49+
}
4450
}

0 commit comments

Comments
 (0)