From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 795E41FF0B3 for ; Wed, 11 Nov 2026 14:22:19 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 3A8182190A; Wed, 11 Nov 2026 14:20:09 +0100 (CET) From: Arthur Bied-Charreton To: pve-devel@lists.proxmox.com Subject: [PATCH pve-manager v6 22/28] ui: sdn: apply: add control for dangling IPSet references Date: Wed, 11 Nov 2026 14:18:55 +0100 Message-ID: <20261111131901.1791124-23-a.bied-charreton@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261111131901.1791124-1-a.bied-charreton@proxmox.com> References: <20261111131901.1791124-1-a.bied-charreton@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1794403149067 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.624 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: 5L6BBLFVW2FGPUC6C2OBV3NJOG2HUGQY X-Message-ID-Hash: 5L6BBLFVW2FGPUC6C2OBV3NJOG2HUGQY X-MailFrom: a.bied-charreton@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Applying an SDN configuration that removes a VNet also removes the four IPSets auto-generated for it [0], so rules referencing those no longer resolve and are dropped from the generated ruleset. Replace the plain confirmation message box with a window carrying the shared selector, so those rules can be disabled or deleted in the same step. The Apply button first queries the pending VNets, and the window only shows the selector if the apply actually removes one, since there is nothing to decide otherwise. [0] https://pve.proxmox.com/wiki/Software-Defined_Network#pvesdn_firewall_integration Signed-off-by: Arthur Bied-Charreton --- www/manager6/sdn/StatusView.js | 119 +++++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 20 deletions(-) diff --git a/www/manager6/sdn/StatusView.js b/www/manager6/sdn/StatusView.js index fada5041..2715df61 100644 --- a/www/manager6/sdn/StatusView.js +++ b/www/manager6/sdn/StatusView.js @@ -1,3 +1,88 @@ +// scanned by asciidoc-pve, so the anchor lands in the documentation index +const VNET_IPSETS_HELP = { + onlineHelp: 'pve_firewall_automatically_generated_ipsets', +}; + +Ext.define('PVE.sdn.ApplyWindow', { + extend: 'Proxmox.window.Edit', + alias: 'widget.pveSdnApplyWindow', + + title: gettext('Apply SDN Configuration'), + + url: '/cluster/sdn', + method: 'PUT', + isCreate: true, + submitText: gettext('Apply'), + width: 600, + + removedVnets: [], + + initComponent: function () { + let me = this; + + me.items = [ + { + xtype: 'displayfield', + value: gettext( + 'Applying pending SDN changes will also apply any pending local node network changes.', + ), + }, + ]; + + if (me.removedVnets.length !== 0) { + let removedHint = Ext.htmlEncode( + Ext.String.format( + gettext('This removes the following VNet(s): {0}.'), + me.removedVnets.join(', '), + ), + ); + let helpLink = Ext.htmlEncode(Proxmox.Utils.get_help_link(VNET_IPSETS_HELP.onlineHelp)); + let refsHint = Ext.String.format( + gettext( + 'Firewall rules referencing their auto-generated IPSets will no longer resolve.', + ), + helpLink, + ); + + me.items.push( + { + xtype: 'displayfield', + userCls: 'pmx-hint', + value: `${removedHint}
${refsHint}`, + }, + { + xtype: 'pveFirewallReferenceAction', + name: 'dangling-ipset-references', + preferredValue: 'drop', + fieldLabel: gettext('Referencing rules'), + labelWidth: 200, + referenceActions: [ + { + text: gettext('Keep'), + value: 'keep', + description: gettext( + "Do not touch firewall rules referencing this VNet's IPSets.", + ), + }, + { + text: gettext('Disable'), + value: 'disable', + description: gettext("Disable firewall rules referencing this VNet's IPSets."), + }, + { + text: gettext('Delete'), + value: 'drop', + description: gettext("Delete firewall rules referencing this VNet's IPSets."), + }, + ], + }, + ); + } + + me.callParent(); + }, +}); + Ext.define( 'PVE.sdn.StatusView', { @@ -45,26 +130,20 @@ Ext.define( { text: gettext('Apply'), handler: function () { - Ext.Msg.show({ - title: gettext('Confirm'), - icon: Ext.Msg.QUESTION, - msg: gettext( - 'Applying pending SDN changes will also apply any pending local node network changes. Proceed?', - ), - buttons: Ext.Msg.YESNO, - callback: function (btn) { - if (btn === 'yes') { - Proxmox.Utils.API2Request({ - url: '/cluster/sdn/', - method: 'PUT', - waitMsgTarget: me, - failure: (response) => - Ext.Msg.alert( - gettext('Error'), - response.htmlStatus, - ), - }); - } + Proxmox.Utils.API2Request({ + url: '/cluster/sdn/vnets', + method: 'GET', + params: { pending: 1 }, + waitMsgTarget: me, + failure: (response) => + Ext.Msg.alert(gettext('Error'), response.htmlStatus), + success: function (response) { + Ext.create('PVE.sdn.ApplyWindow', { + removedVnets: response.result.data + .filter((vnet) => vnet.state === 'deleted') + .map((vnet) => vnet.vnet), + autoShow: true, + }); }, }); }, -- 2.47.3