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 50AAE9B9BA for ; Fri, 26 May 2023 09:27:34 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 39755A8E0 for ; Fri, 26 May 2023 09:27:34 +0200 (CEST) Received: from bastionodiso.odiso.net (bastionodiso.odiso.net [IPv6:2a0a:1580:2000::2d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Fri, 26 May 2023 09:27:32 +0200 (CEST) Received: from kvmformation3.odiso.net (formationkvm3.odiso.net [10.3.94.12]) by bastionodiso.odiso.net (Postfix) with ESMTP id 3BED67C72; Fri, 26 May 2023 09:27:26 +0200 (CEST) Received: by kvmformation3.odiso.net (Postfix, from userid 0) id 2DBB42E3C17; Fri, 26 May 2023 09:27:26 +0200 (CEST) From: Alexandre Derumier To: pve-devel@lists.proxmox.com Date: Fri, 26 May 2023 09:27:21 +0200 Message-Id: <20230526072724.1605613-2-aderumier@odiso.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230526072724.1605613-1-aderumier@odiso.com> References: <20230526072724.1605613-1-aderumier@odiso.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.003 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 HEADER_FROM_DIFFERENT_DOMAINS 0.249 From and EnvelopeFrom 2nd level mail domains are different KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pve-devel] [PATCH pve-manager 1/4] add vnet permissions panel 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: Fri, 26 May 2023 07:27:34 -0000 Signed-off-by: Alexandre Derumier --- www/manager6/Makefile | 2 + www/manager6/sdn/Browser.js | 17 +- www/manager6/sdn/VnetACLView.js | 299 +++++++++++++++++++++++++++ www/manager6/sdn/ZoneContentPanel.js | 41 ++++ www/manager6/sdn/ZoneContentView.js | 25 ++- 5 files changed, 366 insertions(+), 18 deletions(-) create mode 100644 www/manager6/sdn/VnetACLView.js create mode 100644 www/manager6/sdn/ZoneContentPanel.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index 2b577c8e..fb9930af 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -251,10 +251,12 @@ JSSRC= \ sdn/StatusView.js \ sdn/VnetEdit.js \ sdn/VnetView.js \ + sdn/VnetACLView.js \ sdn/VnetPanel.js \ sdn/SubnetEdit.js \ sdn/SubnetView.js \ sdn/ZoneContentView.js \ + sdn/ZoneContentPanel.js \ sdn/ZoneView.js \ sdn/OptionsPanel.js \ sdn/controllers/Base.js \ diff --git a/www/manager6/sdn/Browser.js b/www/manager6/sdn/Browser.js index 09b0c4fe..3dc5a5ad 100644 --- a/www/manager6/sdn/Browser.js +++ b/www/manager6/sdn/Browser.js @@ -25,14 +25,15 @@ Ext.define('PVE.sdn.Browser', { const caps = Ext.state.Manager.get('GuiCap'); - if (caps.sdn['SDN.Audit']) { - me.items.push({ - xtype: 'pveSDNZoneContentView', - title: gettext('Content'), - iconCls: 'fa fa-th', - itemId: 'content', - }); - } + me.items.push({ + nodename: nodename, + zone: sdnId, + xtype: 'pveSDNZoneContentPanel', + title: gettext('Content'), + iconCls: 'fa fa-th', + itemId: 'content', + }); + if (caps.sdn['Permissions.Modify']) { me.items.push({ xtype: 'pveACLView', diff --git a/www/manager6/sdn/VnetACLView.js b/www/manager6/sdn/VnetACLView.js new file mode 100644 index 00000000..5a0f1762 --- /dev/null +++ b/www/manager6/sdn/VnetACLView.js @@ -0,0 +1,299 @@ +Ext.define('PVE.sdn.VnetACLAdd', { + extend: 'Proxmox.window.Edit', + alias: ['widget.pveSDNVnetACLAdd'], + + url: '/access/acl', + method: 'PUT', + isAdd: true, + isCreate: true, + + width: 400, + initComponent: function() { + let me = this; + + let items = [ + { + xtype: 'hiddenfield', + name: 'path', + value: me.path, + allowBlank: false, + fieldLabel: gettext('Path'), + }, + ]; + + if (me.aclType === 'group') { + me.subject = gettext("Group Permission"); + items.push({ + xtype: 'pveGroupSelector', + name: 'groups', + fieldLabel: gettext('Group'), + }); + } else if (me.aclType === 'user') { + me.subject = gettext("User Permission"); + items.push({ + xtype: 'pmxUserSelector', + name: 'users', + fieldLabel: gettext('User'), + }); + } else if (me.aclType === 'token') { + me.subject = gettext("API Token Permission"); + items.push({ + xtype: 'pveTokenSelector', + name: 'tokens', + fieldLabel: gettext('API Token'), + }); + } else { + throw "unknown ACL type"; + } + + items.push({ + xtype: 'pmxRoleSelector', + name: 'roles', + value: 'NoAccess', + fieldLabel: gettext('Role'), + }); + + items.push({ + xtype: 'proxmoxintegerfield', + name: 'vlan', + minValue: 1, + maxValue: 4096, + allowBlank: true, + fieldLabel: 'Vlan', + emptyText: gettext('All'), + }); + + if (!me.path) { + items.push({ + xtype: 'proxmoxcheckbox', + name: 'propagate', + checked: true, + uncheckedValue: 0, + fieldLabel: gettext('Propagate'), + }); + } + + let ipanel = Ext.create('Proxmox.panel.InputPanel', { + items: items, + onlineHelp: 'pveum_permission_management', + onGetValues: function(values) { + if (values.vlan) { + values.path = values.path + "." + values.vlan; + delete values.vlan; + } + return values; + }, + }); + + Ext.apply(me, { + items: [ipanel], + }); + + me.callParent(); + }, +}); + +Ext.define('PVE.sdn.VnetACLView', { + extend: 'Ext.grid.GridPanel', + + alias: ['widget.pveSDNVnetACLView'], + + onlineHelp: 'chapter_user_management', + + stateful: true, + stateId: 'grid-acls', + + // use fixed path + path: undefined, + + setPath: function(path) { + let me = this; + + me.path = path; + + if (path === undefined) { + me.down('#groupmenu').setDisabled(true); + me.down('#usermenu').setDisabled(true); + me.down('#tokenmenu').setDisabled(true); + } else { + me.down('#groupmenu').setDisabled(false); + me.down('#usermenu').setDisabled(false); + me.down('#tokenmenu').setDisabled(false); + me.store.load(); + } + }, + initComponent: function() { + let me = this; + + let store = Ext.create('Ext.data.Store', { + model: 'pve-acl', + proxy: { + type: 'proxmox', + url: "/api2/json/access/acl", + }, + sorters: { + property: 'path', + direction: 'ASC', + }, + }); + + store.addFilter(Ext.create('Ext.util.Filter', { + filterFn: item => item.data.path.replace(/(\/sdn\/vnets\/)(.*)\.[0-9]*$/, '$1$2') === me.path, + })); + + let render_ugid = function(ugid, metaData, record) { + if (record.data.type === 'group') { + return '@' + ugid; + } + + return Ext.String.htmlEncode(ugid); + }; + + let render_vlan = function(path, metaData, record) { + let vlan = 'any'; + const match = path.match(/(\/sdn\/vnets\/)(.*)\.([0-9]*)$/); + if (match) { + vlan = match[3]; + } + + return Ext.String.htmlEncode(vlan); + }; + + let columns = [ + { + header: gettext('User') + '/' + gettext('Group') + '/' + gettext('API Token'), + flex: 1, + sortable: true, + renderer: render_ugid, + dataIndex: 'ugid', + }, + { + header: gettext('Role'), + flex: 1, + sortable: true, + dataIndex: 'roleid', + }, + { + header: gettext('Vlan'), + flex: 1, + sortable: true, + renderer: render_vlan, + dataIndex: 'path', + }, + ]; + + + let sm = Ext.create('Ext.selection.RowModel', {}); + + let remove_btn = new Proxmox.button.Button({ + text: gettext('Remove'), + disabled: true, + selModel: sm, + confirmMsg: gettext('Are you sure you want to remove this entry'), + handler: function(btn, event, rec) { + var params = { + 'delete': 1, + path: rec.data.path, + roles: rec.data.roleid, + }; + if (rec.data.type === 'group') { + params.groups = rec.data.ugid; + } else if (rec.data.type === 'user') { + params.users = rec.data.ugid; + } else if (rec.data.type === 'token') { + params.tokens = rec.data.ugid; + } else { + throw 'unknown data type'; + } + + Proxmox.Utils.API2Request({ + url: '/access/acl', + params: params, + method: 'PUT', + waitMsgTarget: me, + callback: () => store.load(), + failure: response => Ext.Msg.alert(gettext('Error'), response.htmlStatus), + }); + }, + }); + + Proxmox.Utils.monStoreErrors(me, store); + + Ext.apply(me, { + store: store, + selModel: sm, + tbar: [ + { + text: gettext('Add'), + menu: { + xtype: 'menu', + items: [ + { + text: gettext('Group Permission'), + disabled: !me.path, + itemId: 'groupmenu', + iconCls: 'fa fa-fw fa-group', + handler: function() { + var win = Ext.create('PVE.sdn.VnetACLAdd', { + aclType: 'group', + path: me.path, + }); + win.on('destroy', () => store.load()); + win.show(); + }, + }, + { + text: gettext('User Permission'), + disabled: !me.path, + itemId: 'usermenu', + iconCls: 'fa fa-fw fa-user', + handler: function() { + var win = Ext.create('PVE.sdn.VnetACLAdd', { + aclType: 'user', + path: me.path, + }); + win.on('destroy', () => store.load()); + win.show(); + }, + }, + { + text: gettext('API Token Permission'), + disabled: !me.path, + itemId: 'tokenmenu', + iconCls: 'fa fa-fw fa-user-o', + handler: function() { + let win = Ext.create('PVE.sdn.VnetACLAdd', { + aclType: 'token', + path: me.path, + }); + win.on('destroy', () => store.load()); + win.show(); + }, + }, + ], + }, + }, + remove_btn, + ], + viewConfig: { + trackOver: false, + }, + columns: columns, + listeners: { + }, + }); + + me.callParent(); + }, +}, function() { + Ext.define('pve-acl-vnet', { + extend: 'Ext.data.Model', + fields: [ + 'path', 'type', 'ugid', 'roleid', + { + name: 'propagate', + type: 'boolean', + }, + ], + }); +}); diff --git a/www/manager6/sdn/ZoneContentPanel.js b/www/manager6/sdn/ZoneContentPanel.js new file mode 100644 index 00000000..5bb081bb --- /dev/null +++ b/www/manager6/sdn/ZoneContentPanel.js @@ -0,0 +1,41 @@ +Ext.define('PVE.sdn.ZoneContentPanel', { + extend: 'Ext.panel.Panel', + alias: 'widget.pveSDNZoneContentPanel', + + title: 'Vnet', + + onlineHelp: 'pvesdn_config_vnet', + + initComponent: function() { + var me = this; + + var permissions_panel = Ext.createWidget('pveSDNVnetACLView', { + title: gettext('Vnet Permissions'), + region: 'center', + border: false, + }); + + var vnetview_panel = Ext.createWidget('pveSDNZoneContentView', { + title: 'Vnets', + region: 'west', + permissions_panel: permissions_panel, + nodename: me.nodename, + zone: me.zone, + width: '50%', + border: false, + split: true, + }); + + Ext.apply(me, { + layout: 'border', + items: [vnetview_panel, permissions_panel], + listeners: { + show: function() { + permissions_panel.fireEvent('show', permissions_panel); + }, + }, + }); + + me.callParent(); + }, +}); diff --git a/www/manager6/sdn/ZoneContentView.js b/www/manager6/sdn/ZoneContentView.js index 1ea65450..08fa9d81 100644 --- a/www/manager6/sdn/ZoneContentView.js +++ b/www/manager6/sdn/ZoneContentView.js @@ -17,17 +17,15 @@ Ext.define('PVE.sdn.ZoneContentView', { initComponent: function() { var me = this; - var nodename = me.pveSelNode.data.node; - if (!nodename) { + if (!me.nodename) { throw "no node name specified"; } - var zone = me.pveSelNode.data.sdn; - if (!zone) { + if (!me.zone) { throw "no zone ID specified"; } - var baseurl = "/nodes/" + nodename + "/sdn/zones/" + zone + "/content"; + var baseurl = "/nodes/" + me.nodename + "/sdn/zones/" + me.zone + "/content"; var store = Ext.create('Ext.data.Store', { model: 'pve-sdnzone-content', groupField: 'content', @@ -48,7 +46,6 @@ Ext.define('PVE.sdn.ZoneContentView', { }; Proxmox.Utils.monStoreErrors(me, store); - Ext.apply(me, { store: store, selModel: sm, @@ -79,11 +76,19 @@ Ext.define('PVE.sdn.ZoneContentView', { dataIndex: 'statusmsg', }, ], - listeners: { - activate: reload, - }, + listeners: { + activate: reload, + show: reload, + select: function(_sm, rec) { + let path = `/sdn/vnets/${rec.data.vnet}`; + me.permissions_panel.setPath(path); + }, + deselect: function() { + me.permissions_panel.setPath(undefined); + }, + }, }); - + store.load(); me.callParent(); }, }, function() { -- 2.30.2