From 3906dadb8a4d8fc8ffe19f110f876b51dd0ff349 Mon Sep 17 00:00:00 2001 From: Anurag Awasthi Date: Fri, 25 Jan 2019 16:10:23 +0530 Subject: [PATCH] server: allow disk offering selection for volume from snapshot Snapshots created for ROOT disk does not have disk offering id therefore when volume is created from them resulting volume also doesn't have any disk offering. This change allows selection of disk offering in UI when creating volumes from such snapshots. Signed-off-by: Abhishek Kumar --- .../cloud/storage/VolumeApiServiceImpl.java | 42 ++++-- ui/scripts/storage.js | 136 +++++++++++++++++- 2 files changed, 160 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 23b56e98da38..c0f6e0125cb9 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -556,7 +556,6 @@ public VolumeVO allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationExcept Long zoneId = cmd.getZoneId(); Long diskOfferingId = null; DiskOfferingVO diskOffering = null; - Storage.ProvisioningType provisioningType; Long size = null; Long minIops = null; Long maxIops = null; @@ -564,11 +563,22 @@ public VolumeVO allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationExcept 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(); @@ -642,13 +652,13 @@ public VolumeVO allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationExcept } } - 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) { @@ -660,19 +670,20 @@ public VolumeVO allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationExcept } 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 + } - provisioningType = diskOffering.getProvisioningType(); // check snapshot permissions _accountMgr.checkAccess(caller, null, true, snapshotCheck); @@ -694,9 +705,10 @@ public VolumeVO allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationExcept // 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 06fe41e2f712..cb7f93944dcd 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,21 +2008,146 @@ } }); } + }, + 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;idiskofferingObjs[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.data.diskOffering) { + $.extend(data, { + diskofferingid: args.data.diskOffering + }); + } + if (args.$form.find('.form-item[rel=zoneid]').css("display") != "none" && args.data.zoneid != '') { $.extend(data, { zoneId: args.data.zoneid }); } + 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 +2164,9 @@ } } }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); } }); }, @@ -2043,7 +2174,6 @@ poll: pollAsyncJobResult } }, - revertSnapshot: { label: 'label.action.revert.snapshot', messages: {