* [PATCH manager v3 0/3] ui: add container mount point idmapping
@ 2026-05-12 14:01 Filip Schauer
2026-05-12 14:01 ` [PATCH manager v3 1/3] ui: lxc/MPEdit: remove duplicate "mp" assignment Filip Schauer
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Filip Schauer @ 2026-05-12 14:01 UTC (permalink / raw)
To: pve-devel
Integrate UID/GID mapping for container mount points into the web UI.
Changes since v2:
* Replace segmented None/Passthrough/Custom button
with passthrough checkbox
* Replace segmented UID/GID button with combobox
* Factor the idmap grid out into its own component
Filip Schauer (3):
ui: lxc/MPEdit: remove duplicate "mp" assignment
d/control: bump versiond dependency for pve-container
ui: lxc/MPEdit: add "idmap" option
debian/control | 2 +-
www/manager6/Makefile | 1 +
www/manager6/lxc/IdMapField.js | 187 +++++++++++++++++++++++++++++++++
www/manager6/lxc/MPEdit.js | 9 +-
4 files changed, 197 insertions(+), 2 deletions(-)
create mode 100644 www/manager6/lxc/IdMapField.js
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH manager v3 1/3] ui: lxc/MPEdit: remove duplicate "mp" assignment 2026-05-12 14:01 [PATCH manager v3 0/3] ui: add container mount point idmapping Filip Schauer @ 2026-05-12 14:01 ` Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 2/3] d/control: bump versioned dependency for pve-container Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 3/3] ui: lxc/MPEdit: add "idmap" option Filip Schauer 2 siblings, 0 replies; 6+ messages in thread From: Filip Schauer @ 2026-05-12 14:01 UTC (permalink / raw) To: pve-devel Signed-off-by: Filip Schauer <f.schauer@proxmox.com> --- www/manager6/lxc/MPEdit.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/manager6/lxc/MPEdit.js b/www/manager6/lxc/MPEdit.js index 4ed2d07b..b1f67741 100644 --- a/www/manager6/lxc/MPEdit.js +++ b/www/manager6/lxc/MPEdit.js @@ -41,7 +41,6 @@ Ext.define('PVE.lxc.MountPointInputPanel', { setMPOpt('mp', values.mp); let mountOpts = (values.mountoptions || []).join(';'); setMPOpt('mountoptions', values.mountoptions, mountOpts); - setMPOpt('mp', values.mp); setMPOpt('backup', values.backup); setMPOpt('quota', values.quota); setMPOpt('ro', values.ro); -- 2.47.3 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH manager v3 2/3] d/control: bump versioned dependency for pve-container 2026-05-12 14:01 [PATCH manager v3 0/3] ui: add container mount point idmapping Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 1/3] ui: lxc/MPEdit: remove duplicate "mp" assignment Filip Schauer @ 2026-05-12 14:01 ` Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 3/3] ui: lxc/MPEdit: add "idmap" option Filip Schauer 2 siblings, 0 replies; 6+ messages in thread From: Filip Schauer @ 2026-05-12 14:01 UTC (permalink / raw) To: pve-devel This is needed for UI integration of container mount point id mapping. Signed-off-by: Filip Schauer <f.schauer@proxmox.com> --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 5a6aec2a..447fbec8 100644 --- a/debian/control +++ b/debian/control @@ -86,7 +86,7 @@ Depends: apt (>= 1.5~), proxmox-termproxy (>= 2.1.0~), proxmox-widget-toolkit (>= 5.1.1), pve-cluster (>= 9.0.1), - pve-container (>= 5.2.5), + pve-container (>= 6.1.6), pve-docs (>= 9.0.5), pve-firewall, pve-ha-manager (>= 5.0.3), -- 2.47.3 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH manager v3 3/3] ui: lxc/MPEdit: add "idmap" option 2026-05-12 14:01 [PATCH manager v3 0/3] ui: add container mount point idmapping Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 1/3] ui: lxc/MPEdit: remove duplicate "mp" assignment Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 2/3] d/control: bump versioned dependency for pve-container Filip Schauer @ 2026-05-12 14:01 ` Filip Schauer 2026-05-12 14:57 ` Wolfgang Bumiller 2 siblings, 1 reply; 6+ messages in thread From: Filip Schauer @ 2026-05-12 14:01 UTC (permalink / raw) To: pve-devel Integrate UID/GID mapping for container mount points into the web UI. Signed-off-by: Filip Schauer <f.schauer@proxmox.com> --- www/manager6/Makefile | 1 + www/manager6/lxc/IdMapField.js | 187 +++++++++++++++++++++++++++++++++ www/manager6/lxc/MPEdit.js | 8 ++ 3 files changed, 196 insertions(+) create mode 100644 www/manager6/lxc/IdMapField.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index f63437d6..85d973fe 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -210,6 +210,7 @@ JSSRC= \ lxc/DNS.js \ lxc/FeaturesEdit.js \ lxc/EnvEdit.js \ + lxc/IdMapField.js \ lxc/MPEdit.js \ lxc/MPResize.js \ lxc/Network.js \ diff --git a/www/manager6/lxc/IdMapField.js b/www/manager6/lxc/IdMapField.js new file mode 100644 index 00000000..93731ae2 --- /dev/null +++ b/www/manager6/lxc/IdMapField.js @@ -0,0 +1,187 @@ +Ext.define('PVE.lxc.IdMapField', { + extend: 'Ext.form.FieldContainer', + xtype: 'pveLxcIdMapField', + + layout: { type: 'vbox', align: 'stretch' }, + + controller: { + xclass: 'Ext.app.ViewController', + + control: { + 'grid proxmoxintegerfield,grid proxmoxKVComboBox': { + change: function (widget, value) { + let me = this; + let record = widget.getWidgetRecord(); + let column = widget.getWidgetColumn(); + if (!record || !column) { + return; + } + record.set(column.dataIndex, value); + record.commit(); + me.updateIdMapField(); + }, + }, + }, + + onIdMapFieldChange: function (field, value) { + let me = this; + let passthrough = value === 'passthrough'; + let checkbox = me.lookup('passthrough'); + checkbox.suspendEvent('change'); + checkbox.setValue(passthrough); + checkbox.resumeEvent('change'); + me.lookup('idmaps').setVisible(!passthrough); + me.lookup('addIdmapButton').setVisible(!passthrough); + + let store = me.lookup('idmaps').getStore(); + if (!passthrough && value) { + store.setData( + value.split(';').map((v) => { + let [type, ct, host, length] = v.split(':'); + return { type, ct, host, length }; + }), + ); + } else { + store.removeAll(); + } + }, + + onPassthroughCheckboxChange: function (checkbox, checked) { + let me = this; + me.lookup('idmap').setValue(checked ? 'passthrough' : ''); + }, + + addIdMap: function () { + let me = this; + me.lookup('idmaps').getStore().add({ type: 'u', ct: '', host: '', length: '' }); + me.updateIdMapField(); + }, + + removeIdMap: function (button) { + let me = this; + me.lookup('idmaps').getStore().remove(button.getWidgetRecord()); + me.updateIdMapField(); + }, + + updateIdMapField: function () { + let me = this; + let value = me + .lookup('idmaps') + .getStore() + .getRange() + .map(({ data: { type, ct, host, length } }) => `${type}:${ct}:${host}:${length}`) + .join(';'); + let field = me.lookup('idmap'); + field.suspendEvent('change'); + field.setValue(value); + field.resumeEvent('change'); + }, + }, + + items: [ + { + xtype: 'proxmoxcheckbox', + reference: 'passthrough', + fieldLabel: gettext('ID Mapping'), + boxLabel: gettext('Passthrough'), + isFormField: false, + listeners: { + change: 'onPassthroughCheckboxChange', + }, + }, + { + xtype: 'grid', + height: 170, + scrollable: true, + reference: 'idmaps', + viewConfig: { + emptyText: gettext('No ID maps configured'), + }, + store: { + fields: ['type', 'ct', 'host', 'length'], + data: [], + }, + columns: [ + { + text: gettext('ID Type'), + xtype: 'widgetcolumn', + dataIndex: 'type', + widget: { + xtype: 'proxmoxKVComboBox', + margin: '4 0', + allowBlank: false, + comboItems: [ + ['u', 'UID'], + ['g', 'GID'], + ], + }, + flex: 1, + }, + { + text: gettext('Container'), + xtype: 'widgetcolumn', + dataIndex: 'ct', + widget: { + xtype: 'proxmoxintegerfield', + margin: '4 0', + emptyText: gettext('Container'), + allowBlank: false, + minValue: 0, + }, + flex: 1, + }, + { + text: gettext('Host'), + xtype: 'widgetcolumn', + dataIndex: 'host', + widget: { + xtype: 'proxmoxintegerfield', + margin: '4 0', + emptyText: gettext('Host'), + allowBlank: false, + minValue: 0, + }, + flex: 1, + }, + { + text: gettext('Range Size'), + xtype: 'widgetcolumn', + dataIndex: 'length', + widget: { + xtype: 'proxmoxintegerfield', + margin: '4 0', + emptyText: gettext('Range Size'), + allowBlank: false, + minValue: 1, + }, + flex: 1, + }, + { + xtype: 'widgetcolumn', + width: 40, + widget: { + xtype: 'button', + margin: '4 0', + iconCls: 'fa fa-trash-o', + handler: 'removeIdMap', + }, + }, + ], + }, + { + xtype: 'button', + reference: 'addIdmapButton', + text: gettext('Add'), + iconCls: 'fa fa-plus-circle', + handler: 'addIdMap', + }, + { + xtype: 'hidden', + reference: 'idmap', + name: 'idmap', + listeners: { + change: 'onIdMapFieldChange', + }, + }, + ], +}); diff --git a/www/manager6/lxc/MPEdit.js b/www/manager6/lxc/MPEdit.js index b1f67741..b193ff89 100644 --- a/www/manager6/lxc/MPEdit.js +++ b/www/manager6/lxc/MPEdit.js @@ -47,6 +47,7 @@ Ext.define('PVE.lxc.MountPointInputPanel', { setMPOpt('acl', values.acl); setMPOpt('replicate', values.replicate); setMPOpt('keepattrs', values.keepattrs); + setMPOpt('idmap', values.idmap); let res = {}; res[confid] = PVE.Parser.printLxcMountPoint(me.mp); @@ -353,6 +354,13 @@ Ext.define('PVE.lxc.MountPointInputPanel', { }, }, ], + + advancedColumnB: [ + { + xtype: 'pveLxcIdMapField', + name: 'idmap', + }, + ], }); Ext.define('PVE.lxc.MountPointEdit', { -- 2.47.3 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH manager v3 3/3] ui: lxc/MPEdit: add "idmap" option 2026-05-12 14:01 ` [PATCH manager v3 3/3] ui: lxc/MPEdit: add "idmap" option Filip Schauer @ 2026-05-12 14:57 ` Wolfgang Bumiller 2026-05-13 9:33 ` superseded: " Filip Schauer 0 siblings, 1 reply; 6+ messages in thread From: Wolfgang Bumiller @ 2026-05-12 14:57 UTC (permalink / raw) To: Filip Schauer; +Cc: pve-devel On Tue, May 12, 2026 at 04:01:21PM +0200, Filip Schauer wrote: > Integrate UID/GID mapping for container mount points into the web UI. Seems better than v1. Some things to consider, though: Checking and then unchecking `passthrough` wipes the list. I wonder if the last state of the list should be kept around as long as the window is open? On the other hand, at least it's a quick and easy way clear and get rid of id mapping, but users would probably be looking for an explicit clear button instead. Then again the list cannot be huge anyway, so it's not really important. (Although the kernel has raised the limit from 5 to 340 lines long ago...) > > Signed-off-by: Filip Schauer <f.schauer@proxmox.com> > --- > www/manager6/Makefile | 1 + > www/manager6/lxc/IdMapField.js | 187 +++++++++++++++++++++++++++++++++ > www/manager6/lxc/MPEdit.js | 8 ++ > 3 files changed, 196 insertions(+) > create mode 100644 www/manager6/lxc/IdMapField.js > > diff --git a/www/manager6/Makefile b/www/manager6/Makefile > index f63437d6..85d973fe 100644 > --- a/www/manager6/Makefile > +++ b/www/manager6/Makefile > @@ -210,6 +210,7 @@ JSSRC= \ > lxc/DNS.js \ > lxc/FeaturesEdit.js \ > lxc/EnvEdit.js \ > + lxc/IdMapField.js \ > lxc/MPEdit.js \ > lxc/MPResize.js \ > lxc/Network.js \ > diff --git a/www/manager6/lxc/IdMapField.js b/www/manager6/lxc/IdMapField.js > new file mode 100644 > index 00000000..93731ae2 > --- /dev/null > +++ b/www/manager6/lxc/IdMapField.js > @@ -0,0 +1,187 @@ > +Ext.define('PVE.lxc.IdMapField', { > + extend: 'Ext.form.FieldContainer', > + xtype: 'pveLxcIdMapField', > + > + layout: { type: 'vbox', align: 'stretch' }, > + > + controller: { > + xclass: 'Ext.app.ViewController', > + > + control: { > + 'grid proxmoxintegerfield,grid proxmoxKVComboBox': { > + change: function (widget, value) { > + let me = this; > + let record = widget.getWidgetRecord(); > + let column = widget.getWidgetColumn(); > + if (!record || !column) { > + return; > + } > + record.set(column.dataIndex, value); > + record.commit(); > + me.updateIdMapField(); > + }, > + }, > + }, > + > + onIdMapFieldChange: function (field, value) { > + let me = this; > + let passthrough = value === 'passthrough'; > + let checkbox = me.lookup('passthrough'); > + checkbox.suspendEvent('change'); > + checkbox.setValue(passthrough); > + checkbox.resumeEvent('change'); > + me.lookup('idmaps').setVisible(!passthrough); > + me.lookup('addIdmapButton').setVisible(!passthrough); > + > + let store = me.lookup('idmaps').getStore(); > + if (!passthrough && value) { > + store.setData( > + value.split(';').map((v) => { > + let [type, ct, host, length] = v.split(':'); > + return { type, ct, host, length }; > + }), > + ); > + } else { > + store.removeAll(); > + } > + }, > + > + onPassthroughCheckboxChange: function (checkbox, checked) { > + let me = this; > + me.lookup('idmap').setValue(checked ? 'passthrough' : ''); > + }, > + > + addIdMap: function () { > + let me = this; > + me.lookup('idmaps').getStore().add({ type: 'u', ct: '', host: '', length: '' }); > + me.updateIdMapField(); > + }, > + > + removeIdMap: function (button) { > + let me = this; > + me.lookup('idmaps').getStore().remove(button.getWidgetRecord()); > + me.updateIdMapField(); > + }, > + > + updateIdMapField: function () { > + let me = this; > + let value = me > + .lookup('idmaps') > + .getStore() > + .getRange() > + .map(({ data: { type, ct, host, length } }) => `${type}:${ct}:${host}:${length}`) > + .join(';'); > + let field = me.lookup('idmap'); > + field.suspendEvent('change'); > + field.setValue(value); > + field.resumeEvent('change'); > + }, > + }, > + > + items: [ > + { > + xtype: 'proxmoxcheckbox', > + reference: 'passthrough', > + fieldLabel: gettext('ID Mapping'), > + boxLabel: gettext('Passthrough'), > + isFormField: false, > + listeners: { > + change: 'onPassthroughCheckboxChange', > + }, > + }, > + { > + xtype: 'grid', > + height: 170, > + scrollable: true, > + reference: 'idmaps', > + viewConfig: { > + emptyText: gettext('No ID maps configured'), > + }, > + store: { > + fields: ['type', 'ct', 'host', 'length'], > + data: [], > + }, > + columns: [ > + { > + text: gettext('ID Type'), > + xtype: 'widgetcolumn', > + dataIndex: 'type', > + widget: { > + xtype: 'proxmoxKVComboBox', > + margin: '4 0', > + allowBlank: false, > + comboItems: [ > + ['u', 'UID'], > + ['g', 'GID'], > + ], > + }, > + flex: 1, > + }, > + { > + text: gettext('Container'), > + xtype: 'widgetcolumn', > + dataIndex: 'ct', > + widget: { > + xtype: 'proxmoxintegerfield', > + margin: '4 0', > + emptyText: gettext('Container'), > + allowBlank: false, > + minValue: 0, > + }, > + flex: 1, > + }, > + { > + text: gettext('Host'), > + xtype: 'widgetcolumn', > + dataIndex: 'host', > + widget: { > + xtype: 'proxmoxintegerfield', > + margin: '4 0', > + emptyText: gettext('Host'), > + allowBlank: false, > + minValue: 0, > + }, > + flex: 1, > + }, > + { > + text: gettext('Range Size'), > + xtype: 'widgetcolumn', > + dataIndex: 'length', > + widget: { > + xtype: 'proxmoxintegerfield', > + margin: '4 0', > + emptyText: gettext('Range Size'), > + allowBlank: false, > + minValue: 1, > + }, > + flex: 1, > + }, > + { > + xtype: 'widgetcolumn', > + width: 40, > + widget: { > + xtype: 'button', > + margin: '4 0', > + iconCls: 'fa fa-trash-o', > + handler: 'removeIdMap', > + }, > + }, > + ], > + }, > + { > + xtype: 'button', > + reference: 'addIdmapButton', > + text: gettext('Add'), > + iconCls: 'fa fa-plus-circle', > + handler: 'addIdMap', > + }, > + { > + xtype: 'hidden', > + reference: 'idmap', > + name: 'idmap', > + listeners: { > + change: 'onIdMapFieldChange', > + }, > + }, > + ], > +}); > diff --git a/www/manager6/lxc/MPEdit.js b/www/manager6/lxc/MPEdit.js > index b1f67741..b193ff89 100644 > --- a/www/manager6/lxc/MPEdit.js > +++ b/www/manager6/lxc/MPEdit.js > @@ -47,6 +47,7 @@ Ext.define('PVE.lxc.MountPointInputPanel', { > setMPOpt('acl', values.acl); > setMPOpt('replicate', values.replicate); > setMPOpt('keepattrs', values.keepattrs); > + setMPOpt('idmap', values.idmap); > > let res = {}; > res[confid] = PVE.Parser.printLxcMountPoint(me.mp); > @@ -353,6 +354,13 @@ Ext.define('PVE.lxc.MountPointInputPanel', { > }, > }, > ], > + > + advancedColumnB: [ > + { > + xtype: 'pveLxcIdMapField', > + name: 'idmap', > + }, > + ], > }); > > Ext.define('PVE.lxc.MountPointEdit', { > -- > 2.47.3 ^ permalink raw reply [flat|nested] 6+ messages in thread
* superseded: Re: [PATCH manager v3 3/3] ui: lxc/MPEdit: add "idmap" option 2026-05-12 14:57 ` Wolfgang Bumiller @ 2026-05-13 9:33 ` Filip Schauer 0 siblings, 0 replies; 6+ messages in thread From: Filip Schauer @ 2026-05-13 9:33 UTC (permalink / raw) To: Wolfgang Bumiller; +Cc: pve-devel On 12/05/2026 16:55, Wolfgang Bumiller wrote: > Seems better than v1. Some things to consider, though: > > Checking and then unchecking `passthrough` wipes the list. > I wonder if the last state of the list should be kept around as long as > the window is open? > On the other hand, at least it's a quick and easy way clear and get rid > of id mapping, but users would probably be looking for an explicit clear > button instead. Then again the list cannot be huge anyway, so it's not > really important. (Although the kernel has raised the limit from 5 to > 340 lines long ago...) Added a "Clear" button next to "Add" and the "Passthrough" checkbox no longer wipes the list in v4: https://lore.proxmox.com/pve-devel/20260513092830.47167-1-f.schauer@proxmox.com ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-05-13 9:33 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-12 14:01 [PATCH manager v3 0/3] ui: add container mount point idmapping Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 1/3] ui: lxc/MPEdit: remove duplicate "mp" assignment Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 2/3] d/control: bump versioned dependency for pve-container Filip Schauer 2026-05-12 14:01 ` [PATCH manager v3 3/3] ui: lxc/MPEdit: add "idmap" option Filip Schauer 2026-05-12 14:57 ` Wolfgang Bumiller 2026-05-13 9:33 ` superseded: " Filip Schauer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox