diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 9e3622886e9..384a3a03a0f 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -3840,6 +3840,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir rootDiskOfferingId = diskOfferingId; diskOfferingId = null; } + if (!customParameters.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) { + customParameters.put(VmDetailConstants.ROOT_DISK_SIZE, String.valueOf(diskSize)); + } } if (!offering.getDiskOfferingStrictness() && overrideDiskOfferingId != null) { rootDiskOfferingId = overrideDiskOfferingId; diff --git a/ui/src/config/section/storage.js b/ui/src/config/section/storage.js index 03688ff0002..a5623b3eb93 100644 --- a/ui/src/config/section/storage.js +++ b/ui/src/config/section/storage.js @@ -332,18 +332,8 @@ export default { label: 'label.action.create.volume', dataView: true, show: (record) => { return record.state === 'BackedUp' }, - args: (record, store) => { - var fields = ['snapshotid', 'name'] - if (record.volumetype === 'ROOT') { - fields.push('diskofferingid') - } - return fields - }, - mapping: { - snapshotid: { - value: (record) => { return record.id } - } - } + popup: true, + component: shallowRef(defineAsyncComponent(() => import('@/views/storage/CreateVolume.vue'))) }, { api: 'revertSnapshot', diff --git a/ui/src/views/storage/CreateVolume.vue b/ui/src/views/storage/CreateVolume.vue index bdf31a6e62c..7f11033c64a 100644 --- a/ui/src/views/storage/CreateVolume.vue +++ b/ui/src/views/storage/CreateVolume.vue @@ -35,7 +35,7 @@ v-model:value="form.name" :placeholder="apiParams.name.description" /> - + @@ -62,7 +62,7 @@ - + @@ -134,6 +134,12 @@ export default { ResourceIcon, TooltipLabel }, + props: { + resource: { + type: Object, + default: () => {} + } + }, data () { return { zones: [], @@ -143,6 +149,11 @@ export default { isCustomizedDiskIOps: false } }, + computed: { + createVolumeFromSnapshot () { + return this.$route.path.startsWith('/snapshot') + } + }, beforeCreate () { this.apiParams = this.$getApiParams('createVolume') }, @@ -155,9 +166,7 @@ export default { this.formRef = ref() this.form = reactive({}) this.rules = reactive({ - name: [{ required: true, message: this.$t('message.error.volume.name') }], zoneid: [{ required: true, message: this.$t('message.error.zone') }], - diskofferingid: [{ required: true, message: this.$t('message.error.select') }], size: [{ required: true, message: this.$t('message.error.custom.disk.size') }], miniops: [{ validator: async (rule, value) => { @@ -176,6 +185,10 @@ export default { } }] }) + if (!this.createVolumeFromSnapshot) { + this.rules.name = [{ required: true, message: this.$t('message.error.volume.name') }] + this.rules.diskofferingid = [{ required: true, message: this.$t('message.error.select') }] + } }, fetchData () { this.loading = true @@ -194,7 +207,9 @@ export default { listall: true }).then(json => { this.offerings = json.listdiskofferingsresponse.diskoffering || [] - this.form.diskofferingid = this.offerings[0].id || '' + if (!this.createVolumeFromSnapshot) { + this.form.diskofferingid = this.offerings[0].id || '' + } this.customDiskOffering = this.offerings[0].iscustomized || false this.isCustomizedDiskIOps = this.offerings[0]?.iscustomizediops || false }).finally(() => { @@ -206,6 +221,9 @@ export default { this.formRef.value.validate().then(() => { const formRaw = toRaw(this.form) const values = this.handleRemoveFields(formRaw) + if (this.createVolumeFromSnapshot) { + values.snapshotid = this.resource.id + } this.loading = true api('createVolume', values).then(response => { this.$pollJob({