From: Filip Schauer <f.schauer@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v3 manager 2/2] ui: lxc: add edit window for device passthrough
Date: Wed, 31 Jan 2024 16:03:17 +0100 [thread overview]
Message-ID: <20240131150317.128465-3-f.schauer@proxmox.com> (raw)
In-Reply-To: <20240131150317.128465-1-f.schauer@proxmox.com>
Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
www/manager6/Makefile | 1 +
www/manager6/Utils.js | 11 ++
www/manager6/lxc/DeviceEdit.js | 190 +++++++++++++++++++++++++++++++++
www/manager6/lxc/Resources.js | 31 +++++-
4 files changed, 232 insertions(+), 1 deletion(-)
create mode 100644 www/manager6/lxc/DeviceEdit.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index dc3c85b1..ca236240 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -187,6 +187,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 cb460201..57528d25 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -1605,6 +1605,17 @@ Ext.define('PVE.Utils', {
}
},
+ lxc_dev_count: 256,
+
+ forEachLxcDev: function(func) {
+ for (let i = 0; i < PVE.Utils.lxc_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..445f8607
--- /dev/null
+++ b/www/manager6/lxc/DeviceEdit.js
@@ -0,0 +1,190 @@
+Ext.define('PVE.lxc.DeviceInputPanel', {
+ extend: 'Proxmox.panel.InputPanel',
+
+ autoComplete: false,
+
+ controller: {
+ xclass: 'Ext.app.ViewController',
+ init: function(view) {
+ let me = this;
+ let vm = this.getViewModel();
+ vm.set('confid', view.confid);
+ },
+ },
+
+ viewModel: {
+ data: {
+ confid: '',
+ },
+
+ formulas: {
+ isCreate: function(get) {
+ return !get('confid');
+ },
+ },
+ },
+
+ setVMConfig: function(vmconfig) {
+ let me = this;
+ me.vmconfig = vmconfig;
+
+ if (!me.confid) {
+ PVE.Utils.forEachLxcDev((i) => {
+ let name = "dev" + i.toString();
+ if (!Ext.isDefined(vmconfig[name])) {
+ me.confid = name;
+ me.down('field[name=devid]').setValue(i);
+ return false;
+ }
+ return undefined;
+ });
+ }
+ },
+
+ onGetValues: function(values) {
+ let me = this;
+ delete values.devid;
+ let val = PVE.Parser.printPropertyString(values, 'path');
+ let ret = {};
+ ret[me.confid] = val;
+ return ret;
+ },
+
+ items: [
+ {
+ xtype: 'proxmoxintegerfield',
+ name: 'devid',
+ fieldLabel: gettext('Passthrough ID'),
+ minValue: 0,
+ maxValue: PVE.Utils.dev_count - 1,
+ hidden: true,
+ allowBlank: false,
+ disabled: true,
+ labelAlign: 'right',
+ bind: {
+ hidden: '{!isCreate}',
+ disabled: '{!isCreate}',
+ },
+ validator: function(value) {
+ let view = this.up('inputpanel');
+ if (!view.vmconfig) {
+ return undefined;
+ }
+ if (Ext.isDefined(view.vmconfig["dev" + value])) {
+ return "Device passthrough is already in use.";
+ }
+ return true;
+ },
+ },
+ {
+ xtype: 'textfield',
+ type: 'device',
+ name: 'path',
+ editable: true,
+ allowBlank: false,
+ fieldLabel: gettext('Device Path'),
+ emptyText: '/dev/xyz',
+ labelAlign: 'right',
+ validator: function(value) {
+ if (value.startsWith('/dev/')) {
+ return true;
+ }
+
+ return "Path has to start with /dev/";
+ },
+ },
+ ],
+
+ advancedColumn1: [
+ {
+ xtype: 'proxmoxintegerfield',
+ name: 'uid',
+ editable: true,
+ fieldLabel: 'UID',
+ emptyText: '0',
+ minValue: 0,
+ labelAlign: 'right',
+ },
+ {
+ xtype: 'proxmoxintegerfield',
+ name: 'gid',
+ editable: true,
+ fieldLabel: 'GID',
+ emptyText: '0',
+ minValue: 0,
+ labelAlign: 'right',
+ },
+ ],
+
+ advancedColumn2: [
+ {
+ xtype: 'textfield',
+ name: 'mode',
+ editable: true,
+ fieldLabel: gettext('Access Mode'),
+ emptyText: '0660',
+ labelAlign: 'right',
+ validator: function(value) {
+ if (/^0[0-7]{3}$|^$/i.test(value)) {
+ return true;
+ }
+
+ return "Access mode has to be an octal number";
+ },
+ },
+ ],
+});
+
+Ext.define('PVE.lxc.DeviceEdit', {
+ extend: 'Proxmox.window.Edit',
+
+ vmconfig: undefined,
+
+ isAdd: true,
+ width: 400,
+
+ initComponent: function() {
+ let me = this;
+
+ me.isCreate = !me.confid;
+
+ let ipanel = Ext.create('PVE.lxc.DeviceInputPanel', {
+ confid: me.confid,
+ pveSelNode: me.pveSelNode,
+ });
+
+ let subject;
+ if (me.isCreate) {
+ subject = gettext('Device');
+ } else {
+ subject = gettext('Device') + ' (' + me.confid + ')';
+ }
+
+ Ext.apply(me, {
+ subject: subject,
+ 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 values = {
+ path: data.path,
+ mode: data.mode,
+ uid: data.uid,
+ gid: data.gid,
+ };
+
+ ipanel.setValues(values);
+ },
+ });
+ },
+});
diff --git a/www/manager6/lxc/Resources.js b/www/manager6/lxc/Resources.js
index 61182ef3..8203d32b 100644
--- a/www/manager6/lxc/Resources.js
+++ b/www/manager6/lxc/Resources.js
@@ -135,6 +135,19 @@ Ext.define('PVE.lxc.RessourceView', {
};
}, true);
+ let deveditor = Proxmox.UserName === 'root@pam' ? 'PVE.lxc.DeviceEdit' : undefined;
+
+ PVE.Utils.forEachLxcDev(function(i) {
+ confid = 'dev' + i;
+ rows[confid] = {
+ group: 7,
+ order: i,
+ tdCls: 'pve-itype-icon-pci',
+ editor: deveditor,
+ header: gettext('Device') + ' (' + confid + ')',
+ };
+ });
+
var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
me.selModel = Ext.create('Ext.selection.RowModel', {});
@@ -311,6 +324,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 +340,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 +394,21 @@ Ext.define('PVE.lxc.RessourceView', {
});
},
},
+ {
+ text: gettext('Device Passthrough'),
+ iconCls: 'pve-itype-icon-pci',
+ disabled: Proxmox.UserName !== 'root@pam',
+ handler: function() {
+ Ext.create('PVE.lxc.DeviceEdit', {
+ autoShow: true,
+ url: `/api2/extjs/${baseurl}`,
+ pveSelNode: me.pveSelNode,
+ listeners: {
+ destroy: () => me.reload(),
+ },
+ });
+ },
+ },
],
}),
},
--
2.39.2
next prev parent reply other threads:[~2024-01-31 15:03 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-31 15:03 [pve-devel] [PATCH v3 manager 0/2] " Filip Schauer
2024-01-31 15:03 ` [pve-devel] [PATCH v3 manager 1/2] utils: clarify naming of LXC mount point utils Filip Schauer
2024-04-15 12:12 ` Fiona Ebner
2024-01-31 15:03 ` Filip Schauer [this message]
2024-04-15 12:12 ` [pve-devel] [PATCH v3 manager 2/2] ui: lxc: add edit window for device passthrough Fiona Ebner
2024-04-16 11:48 ` Filip Schauer
2024-04-16 12:10 ` [pve-devel] [PATCH v3 manager 0/2] " Filip Schauer
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=20240131150317.128465-3-f.schauer@proxmox.com \
--to=f.schauer@proxmox.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.