From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 5639B61FD4 for ; Tue, 15 Sep 2020 14:18:53 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 3E30A1A6C9 for ; Tue, 15 Sep 2020 14:18:23 +0200 (CEST) Received: from mail-qt1-x841.google.com (mail-qt1-x841.google.com [IPv6:2607:f8b0:4864:20::841]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id C92AA1A6B4 for ; Tue, 15 Sep 2020 14:18:20 +0200 (CEST) Received: by mail-qt1-x841.google.com with SMTP id v54so2928312qtj.7 for ; Tue, 15 Sep 2020 05:18:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=M9K9dpFDQgRK1UeuQFHqmEgcyxd+PkJQDNnTAv7mYIc=; b=j7vJOoEi/EmvcuoaUxjgXwjZI9NG14JGpSwPfDTpVnknOEy5SU4PN4/9aYK63dANGH grUMnRlB89cgfZnFsrHB6y6dKVQQzKVwvbwbF5XeBeGRxbFa+UsPpcBsG4TxvmN82yPV cjb1cyliR85bZOh8w8kUct9584BqfvrxIgMjCC1RfncBLavxXEe/1gbdp+5bh3nDNsQ/ F6r9u/KIsnFpnSVWKc0vS3msHyZcym3559MNDtAGqeqs9+DLsxgs6dp4EOGjT1SRSpCt ZDKrPVJc5kK9dU41yiAfkzAszTCxA+0lp2aRihJRmplx8wHD+l0vrIDwK+qMi66gn1FM PgCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=M9K9dpFDQgRK1UeuQFHqmEgcyxd+PkJQDNnTAv7mYIc=; b=oPM9ZRiuI9huOqZFAedd26WDYKjnwQ9EFl6rfDW8h9IrFrE+xHlY9kWSHbOW0LxHDX 6682vZuoMUu6gJd3SxL4CGcx5GK8A9l7T3AXhts+CuAythx+Gq4lALkTMqhIBVtQC7Nt MKmVvJa3JW2qLzSCNObXVTWY0RCm6VTNQM5FVXPHzc07Pa++lYKGbcmpdL2yMGimkTwa 08/4qwNSBlB6eZwwul2dmsbCHI3Wm5v6Vq7HA0qOwL8u1eMtqmuXI2AkJeTfem9CXmxm /7ryFjreCgWtqh88Y6KfYtIz/q/HsrAMz7u5JIptwRNYbcVyQcM2EwqEWfKDU0nU1MvS 9wMw== X-Gm-Message-State: AOAM531MA79OhYWt2CKufXZFi72fhDXRiVlM2IFyFk7+eS+P9ToXVDPR XcG6uv6CfH5xrWwsryEvR544Ji/LzyMmVasZW4yqolUS4IY= X-Google-Smtp-Source: ABdhPJzsrHJKlG6c2vPRJi51V3tRmYRTHgxGjV0X6CPt0TbQKATj/A7wH4yiF9CAUZCu4YSXo87XRTWCmnpW/ZR0ll8= X-Received: by 2002:ac8:1667:: with SMTP id x36mr17750297qtk.51.1600172293761; Tue, 15 Sep 2020 05:18:13 -0700 (PDT) MIME-Version: 1.0 References: <20200915113324.313395-1-d.jaeger@proxmox.com> <20200915113324.313395-3-d.jaeger@proxmox.com> In-Reply-To: <20200915113324.313395-3-d.jaeger@proxmox.com> From: Gilberto Nunes Date: Tue, 15 Sep 2020 09:17:37 -0300 Message-ID: To: Proxmox VE development discussion X-SPAM-LEVEL: Spam detection results: 0 AWL 0.083 Adjusted score from AWL reputation of From: address DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain FREEMAIL_ENVFROM_END_DIGIT 0.25 Envelope-from freemail username ends in digit FREEMAIL_FROM 0.001 Sender email is commonly abused enduser mail provider HTML_MESSAGE 0.001 HTML included in message RCVD_IN_DNSWL_NONE -0.0001 Sender listed at https://www.dnswl.org/, no trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [params.storage, proxmox.com, caps.storage] Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Content-Filtered-By: Mailman/MimeDel 2.1.29 Subject: Re: [pve-devel] [PATCH manager v4 2/2] Hardware View: Add GUI for importdisk X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Sep 2020 12:18:53 -0000 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 =C3=A0s 08:34, Dominic J=C3=A4ger escreveu: > Make importing single disks easier. > Required to import a whole VM via GUI. > > Signed-off-by: Dominic J=C3=A4ger > --- > 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 =3D me.vmconfig[values.unusedId]; > confid =3D values.controller + values.deviceid; > - } else if (me.isCreate) { > + } else if (me.isCreate && !me.isImport) { > + // disk format & size should not be part of propertyString fo= r > import > if (values.hdimage) { > me.drive.file =3D 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 =3D ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr']; > - Ext.Array.each(names, function(name) { > - var burst_name =3D name + '_max'; > + var names =3D ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr']; > + Ext.Array.each(names, function(name) { > + var burst_name =3D name + '_max'; > PVE.Utils.propertyStringSet(me.drive, values[name], name); > PVE.Utils.propertyStringSet(me.drive, values[burst_name], > burst_name); > - }); > - > - > - params[confid] =3D PVE.Parser.printQemuDrive(me.drive); > - > + }); > + if (me.isImport) { > + params.device_options =3D > PVE.Parser.printPropertyString(me.drive); > + params.source =3D values.sourceType =3D=3D=3D 'storage' > + ? values.sourceVolid : values.sourcePath; > + params.device =3D values.controller + values.deviceid; > + params.storage =3D values.hdstorage; > + if (values.diskformat) params.format =3D values.diskformat; > + } else { > + params[confid] =3D PVE.Parser.printQemuDrive(me.drive); > + } > return params; > }, > > @@ -169,10 +176,14 @@ Ext.define('PVE.qemu.HDInputPanel', { > me.advancedColumn2 =3D []; > > if (!me.confid || me.unused) { > + let controllerColumn =3D me.isImport ? me.column2 : me.column= 1; > me.bussel =3D Ext.create('PVE.form.ControllerSelector', { > vmconfig: me.insideWizard ? {ide2: 'cdrom'} : {} > }); > - me.column1.push(me.bussel); > + if (me.isImport) { > + me.bussel.fieldLabel =3D 'Target Device'; > + } > + controllerColumn.push(me.bussel); > > me.scsiController =3D 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 =3D { > 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 =3D 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 =3D (element, value) =3D> { > + element.setHidden(!value); > + element.setDisabled(!value); > + }; > + me.sourceRadioStorage =3D Ext.create('Ext.form.field.Radio', = { > + name: 'sourceType', > + inputValue: 'storage', > + boxLabel: gettext('Use a storage as source'), > + checked: true, > + hidden: Proxmox.UserName !=3D=3D 'root@pam', > + listeners: { > + added: () =3D> show(me.sourcePathTextfield, false), > + change: (_, storageRadioChecked) =3D> { > + show(me.sourcePathTextfield, !storageRadioChecked= ); > + let selectors =3D [ > + me.sourceStorageSelector, > + me.sourceFileSelector, > + ]; > + for (const selector of selectors) { > + show(selector, storageRadioChecked); > + } > + }, > + }, > + }); > + me.sourceStorageSelector =3D > 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 =3D Ext.create('PVE.form.FileSelector',= { > + name: 'sourceVolid', > + nodename: me.nodename, > + storageContent: 'images', > + fieldLabel: gettext('Source Image'), > + }); > + me.sourceRadioPath =3D Ext.create('Ext.form.field.Radio', { > + name: 'sourceType', > + inputValue: 'path', > + boxLabel: gettext('Use an absolute path as source'), > + hidden: Proxmox.UserName !=3D=3D 'root@pam', > + }); > + me.sourcePathTextfield =3D Ext.create('Ext.form.field.Text', = { > + xtype: 'textfield', > + fieldLabel: gettext('Source Path'), > + name: 'sourcePath', > + emptyText: '/home/user/disk.qcow2', > + hidden: Proxmox.UserName !=3D=3D '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 =3D gettext('Unused Disk'); > + } else if (me.isImport) { > + me.subject =3D gettext('Import Disk'); > + me.submitText =3D 'Import'; > + me.backgroundDelay =3D undefined; > } else if (me.isCreate) { > - me.subject =3D gettext('Hard Disk'); > + me.subject =3D gettext('Hard Disk'); > } else { > me.subject =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 >