Make importing single disks easier.
Required to import a whole VM via GUI.

Signed-off-by: Dominic Jäger <d.jae...@proxmox.com>
---
 www/manager6/qemu/HDEdit.js       | 134 ++++++++++++++++++++++++++----
 www/manager6/qemu/HardwareView.js |  24 ++++++
 2 files changed, 141 insertions(+), 17 deletions(-)

diff --git a/www/manager6/qemu/HDEdit.js b/www/manager6/qemu/HDEdit.js
index e2a5b914..5e0a3981 100644
--- a/www/manager6/qemu/HDEdit.js
+++ b/www/manager6/qemu/HDEdit.js
@@ -67,7 +67,8 @@ Ext.define('PVE.qemu.HDInputPanel', {
        if (me.unused) {
            me.drive.file = me.vmconfig[values.unusedId];
            confid = values.controller + values.deviceid;
-       } else if (me.isCreate) {
+       } else if (me.isCreate && !me.isImport) {
+           // disk format & size should not be part of propertyString for 
import
            if (values.hdimage) {
                me.drive.file = values.hdimage;
            } else {
@@ -83,16 +84,22 @@ Ext.define('PVE.qemu.HDInputPanel', {
        PVE.Utils.propertyStringSet(me.drive, values.iothread, 'iothread', 
'on');
        PVE.Utils.propertyStringSet(me.drive, values.cache, 'cache');
 
-        var names = ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr'];
-        Ext.Array.each(names, function(name) {
-            var burst_name = name + '_max';
+       var names = ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr'];
+       Ext.Array.each(names, function(name) {
+           var burst_name = name + '_max';
            PVE.Utils.propertyStringSet(me.drive, values[name], name);
            PVE.Utils.propertyStringSet(me.drive, values[burst_name], 
burst_name);
-        });
-
-
-       params[confid] = PVE.Parser.printQemuDrive(me.drive);
-
+       });
+       if (me.isImport) {
+           params.device_options = PVE.Parser.printPropertyString(me.drive);
+           params.source = values.sourceType === 'storage'
+               ? values.sourceVolid : values.sourcePath;
+           params.device = values.controller + values.deviceid;
+           params.storage = values.hdstorage;
+           if (values.diskformat) params.format = values.diskformat;
+       } else {
+           params[confid] = PVE.Parser.printQemuDrive(me.drive);
+       }
        return params;
     },
 
@@ -169,10 +176,14 @@ Ext.define('PVE.qemu.HDInputPanel', {
        me.advancedColumn2 = [];
 
        if (!me.confid || me.unused) {
+           let controllerColumn = me.isImport ? me.column2 : me.column1;
            me.bussel = Ext.create('PVE.form.ControllerSelector', {
                vmconfig: me.insideWizard ? {ide2: 'cdrom'} : {}
            });
-           me.column1.push(me.bussel);
+           if (me.isImport) {
+               me.bussel.fieldLabel = 'Target Device';
+           }
+           controllerColumn.push(me.bussel);
 
            me.scsiController = Ext.create('Ext.form.field.Display', {
                fieldLabel: gettext('SCSI Controller'),
@@ -184,7 +195,7 @@ Ext.define('PVE.qemu.HDInputPanel', {
                submitValue: false,
                hidden: true
            });
-           me.column1.push(me.scsiController);
+           controllerColumn.push(me.scsiController);
        }
 
        if (me.unused) {
@@ -199,14 +210,21 @@ Ext.define('PVE.qemu.HDInputPanel', {
                allowBlank: false
            });
            me.column1.push(me.unusedDisks);
-       } else if (me.isCreate) {
-           me.column1.push({
+       } else if (me.isCreate || me.isImport) {
+           let selector = {
                xtype: 'pveDiskStorageSelector',
                storageContent: 'images',
                name: 'disk',
                nodename: me.nodename,
-               autoSelect: me.insideWizard
-           });
+               hideSize: me.isImport,
+               autoSelect: me.insideWizard || me.isImport,
+           };
+           if (me.isImport) {
+               selector.storageLabel = gettext('Target storage');
+               me.column2.push(selector);
+           } else {
+               me.column1.push(selector);
+           }
        } else {
            me.column1.push({
                xtype: 'textfield',
@@ -217,6 +235,12 @@ Ext.define('PVE.qemu.HDInputPanel', {
            });
        }
 
+       if (me.isImport) {
+           me.column2.push({
+               xtype: 'box',
+               autoEl: { tag: 'hr' },
+           });
+       }
        me.column2.push(
            {
                xtype: 'CacheTypeSelector',
@@ -231,6 +255,74 @@ Ext.define('PVE.qemu.HDInputPanel', {
                name: 'discard'
            }
        );
+       if (me.isImport) {
+           let show = (element, value) => {
+               element.setHidden(!value);
+               element.setDisabled(!value);
+           };
+           me.sourceRadioStorage = Ext.create('Ext.form.field.Radio', {
+               name: 'sourceType',
+               inputValue: 'storage',
+               boxLabel: gettext('Use a storage as source'),
+               checked: true,
+               hidden: Proxmox.UserName !== 'root@pam',
+               listeners: {
+                   added: () => show(me.sourcePathTextfield, false),
+                   change: (_, storageRadioChecked) => {
+                       show(me.sourcePathTextfield, !storageRadioChecked);
+                       let selectors = [
+                           me.sourceStorageSelector,
+                           me.sourceFileSelector,
+                       ];
+                       for (const selector of selectors) {
+                           show(selector, storageRadioChecked);
+                       }
+                   },
+               },
+           });
+           me.sourceStorageSelector = Ext.create('PVE.form.StorageSelector', {
+               name: 'inputImageStorage',
+               nodename: me.nodename,
+               fieldLabel: gettext('Source Storage'),
+               storageContent: 'images',
+               autoSelect: me.insideWizard,
+               listeners: {
+                   change: function(_, selectedStorage) {
+                       me.sourceFileSelector.setStorage(selectedStorage);
+                   },
+               },
+           });
+           me.sourceFileSelector = Ext.create('PVE.form.FileSelector', {
+               name: 'sourceVolid',
+               nodename: me.nodename,
+               storageContent: 'images',
+               fieldLabel: gettext('Source Image'),
+           });
+           me.sourceRadioPath = Ext.create('Ext.form.field.Radio', {
+               name: 'sourceType',
+               inputValue: 'path',
+               boxLabel: gettext('Use an absolute path as source'),
+               hidden: Proxmox.UserName !== 'root@pam',
+           });
+           me.sourcePathTextfield = Ext.create('Ext.form.field.Text', {
+               xtype: 'textfield',
+               fieldLabel: gettext('Source Path'),
+               name: 'sourcePath',
+               emptyText: '/home/user/disk.qcow2',
+               hidden: Proxmox.UserName !== 'root@pam',
+               validator: function(insertedText) {
+                   return insertedText.startsWith('/') ||
+                       gettext('Must be an absolute path');
+               },
+           });
+           me.column1.unshift(
+               me.sourceRadioStorage,
+               me.sourceStorageSelector,
+               me.sourceFileSelector,
+               me.sourceRadioPath,
+               me.sourcePathTextfield,
+           );
+       }
 
        me.advancedColumn1.push(
            {
@@ -372,14 +464,19 @@ Ext.define('PVE.qemu.HDEdit', {
            confid: me.confid,
            nodename: nodename,
            unused: unused,
-           isCreate: me.isCreate
+           isCreate: me.isCreate,
+           isImport: me.isImport,
        });
 
        var subject;
        if (unused) {
            me.subject = gettext('Unused Disk');
+       } else if (me.isImport) {
+           me.subject = gettext('Import Disk');
+           me.submitText = 'Import';
+           me.backgroundDelay = undefined;
        } else if (me.isCreate) {
-            me.subject = gettext('Hard Disk');
+           me.subject = gettext('Hard Disk');
        } else {
            me.subject = gettext('Hard Disk') + ' (' + me.confid + ')';
        }
@@ -404,6 +501,9 @@ Ext.define('PVE.qemu.HDEdit', {
                    ipanel.setDrive(drive);
                    me.isValid(); // trigger validation
                }
+               if (me.isImport) {
+                   me.url = me.url.replace(/\/config$/, "/importdisk");
+               }
            }
        });
     }
diff --git a/www/manager6/qemu/HardwareView.js 
b/www/manager6/qemu/HardwareView.js
index 40b3fe86..dc5e217e 100644
--- a/www/manager6/qemu/HardwareView.js
+++ b/www/manager6/qemu/HardwareView.js
@@ -436,6 +436,29 @@ Ext.define('PVE.qemu.HardwareView', {
            handler: run_move
        });
 
+       var import_btn = new Proxmox.button.Button({
+           text: gettext('Import disk'),
+           hidden: !(
+               caps.storage['Datastore.Audit'] &&
+               caps.storage['Datastore.Allocate'] &&
+               caps.storage['Datastore.AllocateTemplate'] &&
+               caps.storage['Datastore.AllocateSpace'] &&
+               caps.vms['VM.Allocate'] &&
+               caps.vms['VM.Config.Disk'] &&
+               true
+           ),
+           handler: function() {
+               var win = Ext.create('PVE.qemu.HDEdit', {
+                   method: 'POST',
+                   url: `/api2/extjs/${baseurl}`,
+                   pveSelNode: me.pveSelNode,
+                   isImport: true,
+               });
+               win.on('destroy', me.reload, me);
+               win.show();
+           },
+       });
+
        var remove_btn = new Proxmox.button.Button({
            text: gettext('Remove'),
            defaultText: gettext('Remove'),
@@ -752,6 +775,7 @@ Ext.define('PVE.qemu.HardwareView', {
                edit_btn,
                resize_btn,
                move_btn,
+               import_btn,
                revert_btn
            ],
            rows: rows,
-- 
2.20.1


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to