This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/master by this push:
new 1b79466 server: allow disk offering selection for volume from
snapshot (#3246)
1b79466 is described below
commit 1b79466dd94a12f1b14dd1e5fc51e2e54b578c67
Author: Abhishek Kumar <[email protected]>
AuthorDate: Tue Jun 25 22:00:24 2019 +0530
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 <[email protected]>
---
.../com/cloud/storage/VolumeApiServiceImpl.java | 47 ++++---
ui/scripts/storage.js | 137 ++++++++++++++++++++-
2 files changed, 166 insertions(+), 18 deletions(-)
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index 37f6d95..099f88b 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -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));
diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js
index f1d3330..789af42 100644
--- a/ui/scripts/storage.js
+++ b/ui/scripts/storage.js
@@ -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: {