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 2CA849B8F4 for ; Tue, 21 Nov 2023 11:21:39 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 023696449 for ; Tue, 21 Nov 2023 11:21:09 +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 ; Tue, 21 Nov 2023 11:21:05 +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 F396540E3B for ; Tue, 21 Nov 2023 11:21:04 +0100 (CET) From: Filip Schauer To: pve-devel@lists.proxmox.com Date: Tue, 21 Nov 2023 11:21:00 +0100 Message-Id: <20231121102100.118669-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.198 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 T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pve-devel] [PATCH v2 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: Tue, 21 Nov 2023 10:21:39 -0000 Signed-off-by: Filip Schauer --- Changes since v1: * Remove usb mapping * Add mode, uid and gid fields To get this to build on top of the current master cd731902b7a7, comment out the call to $notification_config->add_matcher in PVE/VZDump.pm for now. www/manager6/Makefile | 1 + www/manager6/Utils.js | 11 +++ www/manager6/lxc/DeviceEdit.js | 166 +++++++++++++++++++++++++++++++++ www/manager6/lxc/Resources.js | 28 +++++- 4 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 www/manager6/lxc/DeviceEdit.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index ee09f0b8..e18bb66e 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 9f44e560..f028685b 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..1ee4f309 --- /dev/null +++ b/www/manager6/lxc/DeviceEdit.js @@ -0,0 +1,166 @@ +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 = values.path; + delete values.path; + + if (values.mode) { + val += ',mode=' + values.mode; + } + delete values.mode; + + if (values.uid) { + val += ',uid=' + values.uid; + } + delete values.uid; + + if (values.gid) { + val += ',gid=' + values.gid; + } + delete values.gid; + + values[me.confid] = val; + return values; + }, + + items: [ + { + xtype: 'textfield', + type: 'device', + name: 'path', + cbind: { pveSelNode: '{pveSelNode}' }, + editable: true, + allowBlank: false, + fieldLabel: gettext('Device Path'), + labelAlign: 'right', + validator: function(value) { + if (value.startsWith('/dev/')) { + return true; + } + + return "Path has to start with /dev/"; + }, + }, + ], + + advancedColumn1: [ + { + xtype: 'textfield', + name: 'mode', + cbind: { pveSelNode: '{pveSelNode}' }, + editable: true, + fieldLabel: gettext('Access Mode'), + labelAlign: 'right', + validator: function(value) { + if (/^0[0-7]{3}$|^$/i.test(value)) { + return true; + } + + return "Access mode has to be an octal number"; + }, + }, + { + xtype: 'proxmoxintegerfield', + name: 'uid', + cbind: { pveSelNode: '{pveSelNode}' }, + editable: true, + fieldLabel: 'UID', + minValue: 0, + labelAlign: 'right', + }, + { + xtype: 'proxmoxintegerfield', + name: 'gid', + cbind: { pveSelNode: '{pveSelNode}' }, + editable: true, + fieldLabel: 'GID', + minValue: 0, + 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, mode, uid, gid; + path = data.path; + mode = data.mode; + uid = data.uid; + gid = data.gid; + + var values = { + path, + mode, + uid, + gid, + }; + + 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