public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Gilberto Nunes <gilberto.nunes32@gmail.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>
Subject: Re: [pve-devel] [PATCH manager v4 2/2] Hardware View: Add GUI for importdisk
Date: Tue, 15 Sep 2020 09:17:37 -0300	[thread overview]
Message-ID: <CAOKSTBvEzcM6-AOCiQxN2qZ68EX6ZwPK8XTWJCTxtdcGKkr9hg@mail.gmail.com> (raw)
In-Reply-To: <20200915113324.313395-3-d.jaeger@proxmox.com>

I'm looking forward to test this new feature.
Sometimes is really annoying make importdisk from cli.
I also would like to recommend add some feature to import OVA/OVF images
using WEB interface, if this is possible, of course.

Thanks for such wonderful work!

---
Gilberto Nunes Ferreira



Em ter., 15 de set. de 2020 às 08:34, Dominic Jäger <d.jaeger@proxmox.com>
escreveu:

> Make importing single disks easier.
> Required to import a whole VM via GUI.
>
> Signed-off-by: Dominic Jäger <d.jaeger@proxmox.com>
> ---
> v3->v4:
> * Reuse propertyStringSet instead of building it myself
> * More detailed permissions
> * Reorder GUI elements such that source is first
> * Assemble importdisk URL here instead of widget-toolkit & use regex for
>   correct replacement
> * Allow selecting images from PVE storages (Normal users + root) or all
> paths
>   (root)
>
>  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	other threads:[~2020-09-15 12:18 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-15 11:33 [pve-devel] [PATCH v4 0/2] Close #2886: " Dominic Jäger
2020-09-15 11:33 ` [pve-devel] [PATCH qemu-server v4 1/2] Move importdisk from qm to API Dominic Jäger
2020-10-28 13:01   ` Fabian Grünbichler
2020-09-15 11:33 ` [pve-devel] [PATCH manager v4 2/2] Hardware View: Add GUI for importdisk Dominic Jäger
2020-09-15 12:17   ` Gilberto Nunes [this message]
2020-09-16  7:43   ` Dominic Jäger
2020-09-15 15:37 Alexandre - H3TI

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAOKSTBvEzcM6-AOCiQxN2qZ68EX6ZwPK8XTWJCTxtdcGKkr9hg@mail.gmail.com \
    --to=gilberto.nunes32@gmail.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal