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 437039E106 for ; Mon, 30 Oct 2023 12:27:50 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 24253E90C for ; Mon, 30 Oct 2023 12:27:50 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (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 firstgate.proxmox.com (Proxmox) with ESMTPS for ; Mon, 30 Oct 2023 12:27:49 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 276BB42718 for ; Mon, 30 Oct 2023 12:27:49 +0100 (CET) From: Filip Schauer To: pve-devel@lists.proxmox.com Date: Mon, 30 Oct 2023 12:27:42 +0100 Message-Id: <20231030112742.44609-1-f.schauer@proxmox.com> X-Mailer: git-send-email 2.39.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.220 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH manager] ui: lxc: add edit window for device passthrough 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: Mon, 30 Oct 2023 11:27:50 -0000 Signed-off-by: Filip Schauer --- Depends on: https://lists.proxmox.com/pipermail/pve-devel/2023-October/059616.html www/manager6/Makefile | 1 + www/manager6/Utils.js | 11 +++ www/manager6/lxc/DeviceEdit.js | 158 +++++++++++++++++++++++++++++++++ www/manager6/lxc/Resources.js | 28 +++++- 4 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 www/manager6/lxc/DeviceEdit.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index 57e1b48f..373c8f6d 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -185,6 +185,7 @@ JSSRC= \ lxc/CmdMenu.js \ lxc/Config.js \ lxc/CreateWizard.js \ + lxc/DeviceEdit.js \ lxc/DNS.js \ lxc/FeaturesEdit.js \ lxc/MPEdit.js \ diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js index 8f46c07e..1ea7b42a 100644 --- a/www/manager6/Utils.js +++ b/www/manager6/Utils.js @@ -1605,6 +1605,17 @@ Ext.define('PVE.Utils', { } }, + dev_count: 256, + + forEachDev: function(func) { + for (let i = 0; i < PVE.Utils.dev_count; i++) { + let cont = func(i); + if (!cont && cont !== undefined) { + return; + } + } + }, + hardware_counts: { net: 32, usb: 14, diff --git a/www/manager6/lxc/DeviceEdit.js b/www/manager6/lxc/DeviceEdit.js new file mode 100644 index 00000000..e4790c4e --- /dev/null +++ b/www/manager6/lxc/DeviceEdit.js @@ -0,0 +1,158 @@ +Ext.define('PVE.lxc.DeviceInputPanel', { + extend: 'Proxmox.panel.InputPanel', + mixins: ['Proxmox.Mixin.CBind'], + + autoComplete: false, + + cbindData: function(initialConfig) { + let me = this; + if (!me.pveSelNode) { + throw "no pveSelNode given"; + } + + return { nodename: me.pveSelNode.data.node }; + }, + + viewModel: { + data: {}, + }, + + setVMConfig: function(vmconfig) { + var me = this; + me.vmconfig = vmconfig; + }, + + onGetValues: function(values) { + var me = this; + if (!me.confid) { + let max_devices = 256; + for (let i = 0; i < max_devices; i++) { + let id = 'dev' + i.toString(); + if (!me.vmconfig[id]) { + me.confid = id; + break; + } + } + } + var val = ""; + var type = me.down('radiofield').getGroupValue(); + switch (type) { + case 'path': + val = values[type]; + delete values[type]; + break; + case 'usbmapped': + val = 'usbmapping=' + values[type]; + delete values[type]; + break; + default: + throw "invalid type selected"; + } + + values[me.confid] = val; + return values; + }, + + items: [ + { + xtype: 'fieldcontainer', + defaultType: 'radiofield', + layout: 'fit', + items: [ + { + name: 'dev', + inputValue: 'usbmapped', + boxLabel: gettext('Use mapped USB device'), + reference: 'usbmapped', + submitValue: false, + checked: true, + }, + { + xtype: 'pveUSBMapSelector', + disabled: true, + name: 'usbmapped', + cbind: { nodename: '{nodename}' }, + bind: { disabled: '{!usbmapped.checked}' }, + allowBlank: false, + fieldLabel: gettext('Choose Device'), + labelAlign: 'right', + }, + { + name: 'dev', + inputValue: 'path', + boxLabel: gettext('Use Device Path'), + reference: 'path', + submitValue: false, + }, + { + xtype: 'textfield', + disabled: true, + type: 'device', + name: 'path', + cbind: { pveSelNode: '{pveSelNode}' }, + bind: { disabled: '{!path.checked}' }, + editable: true, + allowBlank: false, + fieldLabel: gettext('Device Path'), + labelAlign: 'right', + }, + ], + }, + ], +}); + +Ext.define('PVE.lxc.DeviceEdit', { + extend: 'Proxmox.window.Edit', + + vmconfig: undefined, + + isAdd: true, + width: 400, + subject: gettext('Device'), + + initComponent: function() { + var me = this; + + me.isCreate = !me.confid; + + var ipanel = Ext.create('PVE.lxc.DeviceInputPanel', { + confid: me.confid, + pveSelNode: me.pveSelNode, + }); + + Ext.apply(me, { + items: [ipanel], + }); + + me.callParent(); + + me.load({ + success: function(response, options) { + ipanel.setVMConfig(response.result.data); + if (me.isCreate) { + return; + } + + let data = PVE.Parser.parsePropertyString(response.result.data[me.confid], 'path'); + let path, usbmapped; + let dev; + + if (data.path) { + path = data.path; + dev = 'path'; + } else if (data.usbmapping) { + usbmapped = data.usbmapping; + dev = 'usbmapped'; + } + + var values = { + dev, + path, + usbmapped, + }; + + ipanel.setValues(values); + }, + }); + }, +}); diff --git a/www/manager6/lxc/Resources.js b/www/manager6/lxc/Resources.js index 85112345..9dcb74eb 100644 --- a/www/manager6/lxc/Resources.js +++ b/www/manager6/lxc/Resources.js @@ -135,6 +135,17 @@ Ext.define('PVE.lxc.RessourceView', { }; }, true); + PVE.Utils.forEachDev(function(i) { + confid = 'dev' + i; + rows[confid] = { + group: 7, + order: i, + tdCls: 'pve-itype-icon-pci', + editor: 'PVE.lxc.DeviceEdit', + header: gettext('Device') + ' (' + confid + ')', + }; + }); + var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config'; me.selModel = Ext.create('Ext.selection.RowModel', {}); @@ -311,6 +322,7 @@ Ext.define('PVE.lxc.RessourceView', { let isDisk = isRootFS || key.match(/^(mp|unused)\d+/); let isUnusedDisk = key.match(/^unused\d+/); let isUsedDisk = isDisk && !isUnusedDisk; + let isDevice = key.match(/^dev\d+/); let noedit = isDelete || !rowdef.editor; if (!noedit && Proxmox.UserName !== 'root@pam' && key.match(/^mp\d+$/)) { @@ -326,7 +338,7 @@ Ext.define('PVE.lxc.RessourceView', { reassign_menuitem.setDisabled(isRootFS); resize_menuitem.setDisabled(isUnusedDisk); - remove_btn.setDisabled(!isDisk || isRootFS || !diskCap || pending); + remove_btn.setDisabled(!(isDisk || isDevice) || isRootFS || !diskCap || pending); revert_btn.setDisabled(!pending); remove_btn.setText(isUsedDisk ? remove_btn.altText : remove_btn.defaultText); @@ -380,6 +392,20 @@ Ext.define('PVE.lxc.RessourceView', { }); }, }, + { + text: gettext('Device Passthrough'), + iconCls: 'pve-itype-icon-pci', + handler: function() { + Ext.create('PVE.lxc.DeviceEdit', { + autoShow: true, + url: `/api2/extjs/${baseurl}`, + pveSelNode: me.pveSelNode, + listeners: { + destroy: () => me.reload(), + }, + }); + }, + }, ], }), }, -- 2.39.2