mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
server: allow disk offering selection for volume from snapshot (#3246)
Problem: Volume created from a snapshot does not show its disk offering. Root Cause: The volume created from a snapshot of a root disk does not have a disk offering therefore the disk offering of the created volume from the snapshot is empty. Solution: Refactored createVolume API and extended UI to allow user to select a disk offering while creating a volume using a root disk volume snapshot. For creating volumes using data disk volume snapshot, the disk offering given by the snapshot will be assigned. Disk offering selection in the UI form for volume creation from snapshot is depicted in screenshot below. Signed-off-by: Abhishek Kumar <abhishek.kumar@shapeblue.com>
This commit is contained in:
parent
46752e9af6
commit
1b79466dd9
@ -555,7 +555,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
Long zoneId = cmd.getZoneId();
|
||||
Long diskOfferingId = null;
|
||||
DiskOfferingVO diskOffering = null;
|
||||
Storage.ProvisioningType provisioningType;
|
||||
Long size = null;
|
||||
Long minIops = null;
|
||||
Long maxIops = null;
|
||||
@ -563,11 +562,22 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
VolumeVO parentVolume = null;
|
||||
|
||||
// validate input parameters before creating the volume
|
||||
if ((cmd.getSnapshotId() == null && cmd.getDiskOfferingId() == null) || (cmd.getSnapshotId() != null && cmd.getDiskOfferingId() != null)) {
|
||||
throw new InvalidParameterValueException("Either disk Offering Id or snapshot Id must be passed whilst creating volume");
|
||||
if (cmd.getSnapshotId() == null && cmd.getDiskOfferingId() == null) {
|
||||
throw new InvalidParameterValueException("At least one of disk Offering ID or snapshot ID must be passed whilst creating volume");
|
||||
}
|
||||
|
||||
if (cmd.getSnapshotId() == null) {// create a new volume
|
||||
// disallow passing disk offering ID with DATA disk volume snapshots
|
||||
if (cmd.getSnapshotId() != null && cmd.getDiskOfferingId() != null) {
|
||||
SnapshotVO snapshot = _snapshotDao.findById(cmd.getSnapshotId());
|
||||
if (snapshot != null) {
|
||||
parentVolume = _volsDao.findByIdIncludingRemoved(snapshot.getVolumeId());
|
||||
if (parentVolume != null && parentVolume.getVolumeType() != Volume.Type.ROOT)
|
||||
throw new InvalidParameterValueException("Disk Offering ID cannot be passed whilst creating volume from snapshot other than ROOT disk snapshots");
|
||||
}
|
||||
parentVolume = null;
|
||||
}
|
||||
|
||||
if (cmd.getDiskOfferingId() != null) { // create a new volume
|
||||
|
||||
diskOfferingId = cmd.getDiskOfferingId();
|
||||
size = cmd.getSize();
|
||||
@ -641,13 +651,13 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
}
|
||||
}
|
||||
|
||||
provisioningType = diskOffering.getProvisioningType();
|
||||
|
||||
if (!validateVolumeSizeRange(size)) {// convert size from mb to gb
|
||||
// for validation
|
||||
throw new InvalidParameterValueException("Invalid size for custom volume creation: " + size + " ,max volume size is:" + _maxVolumeSizeInGb);
|
||||
}
|
||||
} else { // create volume from snapshot
|
||||
}
|
||||
|
||||
if (cmd.getSnapshotId() != null) { // create volume from snapshot
|
||||
Long snapshotId = cmd.getSnapshotId();
|
||||
SnapshotVO snapshotCheck = _snapshotDao.findById(snapshotId);
|
||||
if (snapshotCheck == null) {
|
||||
@ -659,19 +669,25 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
}
|
||||
parentVolume = _volsDao.findByIdIncludingRemoved(snapshotCheck.getVolumeId());
|
||||
|
||||
diskOfferingId = snapshotCheck.getDiskOfferingId();
|
||||
diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||
if (zoneId == null) {
|
||||
// if zoneId is not provided, we default to create volume in the same zone as the snapshot zone.
|
||||
zoneId = snapshotCheck.getDataCenterId();
|
||||
}
|
||||
size = snapshotCheck.getSize(); // ; disk offering is used for tags
|
||||
// purposes
|
||||
|
||||
minIops = snapshotCheck.getMinIops();
|
||||
maxIops = snapshotCheck.getMaxIops();
|
||||
if (diskOffering == null) { // Pure snapshot is being used to create volume.
|
||||
diskOfferingId = snapshotCheck.getDiskOfferingId();
|
||||
diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||
|
||||
minIops = snapshotCheck.getMinIops();
|
||||
maxIops = snapshotCheck.getMaxIops();
|
||||
size = snapshotCheck.getSize(); // ; disk offering is used for tags purposes
|
||||
} else {
|
||||
if (size < snapshotCheck.getSize()) {
|
||||
throw new InvalidParameterValueException(String.format("Invalid size for volume creation: %dGB, snapshot size is: %dGB",
|
||||
size / (1024 * 1024 * 1024), snapshotCheck.getSize() / (1024 * 1024 * 1024)));
|
||||
}
|
||||
}
|
||||
|
||||
provisioningType = diskOffering.getProvisioningType();
|
||||
// check snapshot permissions
|
||||
_accountMgr.checkAccess(caller, null, true, snapshotCheck);
|
||||
|
||||
@ -693,9 +709,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
// permission check
|
||||
_accountMgr.checkAccess(caller, null, false, vm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Storage.ProvisioningType provisioningType = diskOffering.getProvisioningType();
|
||||
|
||||
// Check that the resource limit for primary storage won't be exceeded
|
||||
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, displayVolume, new Long(size));
|
||||
|
||||
|
||||
@ -1969,6 +1969,9 @@
|
||||
} else {
|
||||
args.$form.find('.form-item[rel=zoneid]').hide();
|
||||
}
|
||||
if(args.context.snapshots[0].volumetype!='ROOT') {
|
||||
args.$form.find('.form-item[rel=diskOffering]').hide();
|
||||
}
|
||||
},
|
||||
fields: {
|
||||
name: {
|
||||
@ -2005,13 +2008,110 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
diskOffering: {
|
||||
label: 'label.disk.offering',
|
||||
docID: 'helpVolumeDiskOffering',
|
||||
select: function(args) {
|
||||
var snapshotSizeInGB = Math.floor(args.context.snapshots[0].virtualsize/(1024 * 1024 * 1024))
|
||||
$.ajax({
|
||||
url: createURL("listDiskOfferings"),
|
||||
dataType: "json",
|
||||
async: false,
|
||||
success: function(json) {
|
||||
diskofferingObjs = json.listdiskofferingsresponse.diskoffering;
|
||||
var items = [];
|
||||
// Sort offerings list with size and keep custom offerings at end
|
||||
for(var i=0;i<diskofferingObjs.length;i++) {
|
||||
for(var j=i+1;j<diskofferingObjs.length;j++) {
|
||||
if((diskofferingObjs[i].disksize>diskofferingObjs[j].disksize &&
|
||||
diskofferingObjs[j].disksize!=0) ||
|
||||
(diskofferingObjs[i].disksize==0 &&
|
||||
diskofferingObjs[j].disksize!=0)) {
|
||||
var temp = diskofferingObjs[i];
|
||||
diskofferingObjs[i] = diskofferingObjs[j];
|
||||
diskofferingObjs[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
$(diskofferingObjs).each(function() {
|
||||
if(this.disksize==0 || this.disksize>=snapshotSizeInGB) {
|
||||
items.push({
|
||||
id: this.id,
|
||||
description: this.displaytext
|
||||
});
|
||||
}
|
||||
});
|
||||
args.response.success({
|
||||
data: items
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
args.$select.change(function() {
|
||||
var diskOfferingId = $(this).val();
|
||||
selectedDiskOfferingObj = null;
|
||||
$(diskofferingObjs).each(function() {
|
||||
if (this.id == diskOfferingId) {
|
||||
selectedDiskOfferingObj = this;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (selectedDiskOfferingObj == null) return;
|
||||
|
||||
var $form = $(this).closest('form');
|
||||
var $diskSize = $form.find('.form-item[rel=diskSize]');
|
||||
if (selectedDiskOfferingObj.iscustomized == true) {
|
||||
$diskSize.css('display', 'inline-block');
|
||||
$form.find('input[name=diskSize]').val(''+snapshotSizeInGB);
|
||||
} else {
|
||||
$diskSize.hide();
|
||||
}
|
||||
|
||||
var $minIops = $form.find('.form-item[rel=minIops]');
|
||||
var $maxIops = $form.find('.form-item[rel=maxIops]');
|
||||
if (selectedDiskOfferingObj.iscustomizediops == true) {
|
||||
$minIops.css('display', 'inline-block');
|
||||
$maxIops.css('display', 'inline-block');
|
||||
} else {
|
||||
$minIops.hide();
|
||||
$maxIops.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
diskSize: {
|
||||
label: 'label.disk.size.gb',
|
||||
docID: 'helpVolumeSizeGb',
|
||||
validation: {
|
||||
required: true,
|
||||
number: true
|
||||
},
|
||||
isHidden: true
|
||||
},
|
||||
minIops: {
|
||||
label: 'label.disk.iops.min',
|
||||
validation: {
|
||||
required: false,
|
||||
number: true
|
||||
},
|
||||
isHidden: true
|
||||
},
|
||||
maxIops: {
|
||||
label: 'label.disk.iops.max',
|
||||
validation: {
|
||||
required: false,
|
||||
number: true
|
||||
},
|
||||
isHidden: true
|
||||
}
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
var data = {
|
||||
snapshotid: args.context.snapshots[0].id,
|
||||
name: args.data.name
|
||||
name: args.data.name,
|
||||
snapshotid: args.context.snapshots[0].id
|
||||
};
|
||||
|
||||
if (args.$form.find('.form-item[rel=zoneid]').css("display") != "none" && args.data.zoneid != '') {
|
||||
@ -2020,6 +2120,35 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (args.$form.find('.form-item[rel=diskOffering]').css("display") != "none") {
|
||||
if (args.data.diskOffering) {
|
||||
$.extend(data, {
|
||||
diskofferingid: args.data.diskOffering
|
||||
});
|
||||
}
|
||||
if (selectedDiskOfferingObj) {
|
||||
if(selectedDiskOfferingObj.iscustomized == true) {
|
||||
$.extend(data, {
|
||||
size: args.data.diskSize
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedDiskOfferingObj.iscustomizediops == true) {
|
||||
if (args.data.minIops != "" && args.data.minIops > 0) {
|
||||
$.extend(data, {
|
||||
miniops: args.data.minIops
|
||||
});
|
||||
}
|
||||
|
||||
if (args.data.maxIops != "" && args.data.maxIops > 0) {
|
||||
$.extend(data, {
|
||||
maxiops: args.data.maxIops
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: createURL('createVolume'),
|
||||
data: data,
|
||||
@ -2036,6 +2165,9 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function(json) {
|
||||
args.response.error(parseXMLHttpResponse(json));
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -2043,7 +2175,6 @@
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
|
||||
revertSnapshot: {
|
||||
label: 'label.action.revert.snapshot',
|
||||
messages: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user